# 121. 买卖股票的最佳时机

# 题目

给定一个数组,它的第  i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

注意:你不能在买入股票前卖出股票。

输入: [7,1,5,3,6,4]

输出: 5

解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

# 题解

# 遍历

遍历数组,记录之前的最低价格,计算差价

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  let min = prices[0];
  let ans = 0;

  for (let i = 0; i < prices.length; ++i) {
    const cur = prices[i];
    if (cur < min) {
      min = cur;
    } else {
      ans = Math.max(cur - min, ans);
    }
  }
  return ans;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

时间复杂度: O(n) 空间复杂度: O(1)

# 动态规划

状态 dp[i] 表示第 i 天的最大利润

转移方程:

  • i 天操作 dp[i] = A[i] - min(0,..i-1)i 价格减去之前的最低价
  • 不操作 dp[i] = dp[i-1]

=> dp[i] = max(dp[i-1], A[i]-min(0,...,i-1))

边界条件: dp[0] = 0

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  if (prices.length == 0) return 0;
  let dp = [0];
  let min = prices[0];
  for (let i = 1; i < prices.length; ++i) {
    dp[i] = Math.max(dp[i - 1], prices[i] - min);
    min = Math.min(prices[i], min);
  }
  return dp[prices.length - 1];
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

实际只依赖最近的两个状态,进行存储优化

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  if (prices.length == 0) return 0;
  let a = 0,
    b = 0;
  let min = prices[0];
  for (let i = 1; i < prices.length; ++i) {
    b = Math.max(a, prices[i] - min);
    a = b;
    min = Math.min(prices[i], min);
  }
  return b;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16