Skip to content

Latest commit

 

History

History
103 lines (98 loc) · 4.49 KB

股票买卖.md

File metadata and controls

103 lines (98 loc) · 4.49 KB

题目

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 注意你不能在买入股票前卖出股票。
示例 1:

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

示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

解决方案

我们需要找出给定数组中两个数字之间的最大差值(即,最大利润)。此外,第二个数字(卖出价格)必须大于第一个数字(买入价格)。
形式上,对于每组 i 和 j(其中j>i)我们需要找出 max(prices[j]−prices[i])。

方法一:暴力法

public int maxProfit(int[] prices) {
    int maxProfit = 0;
    for (int i = 0; i < prices.length - 1; i++) {
        for (int j = i + 1; j < prices.length; j++) {
            int profit = prices[j] - prices[i];
            if (profit > maxProfit) {
                maxProfit = profit;
            }
        }
    }
    return maxProfit;
}

复杂度分析

  • 时间复杂度:O(n^2)。循环运行 n(n−1)/2次。

方法二:一次遍历

每次计算当前最小值和该值之后所有数的最大值的差值,不断更新当前最大收益。

public int maxProfit(int[] prices) {
    int minPrice = Integer.MAX_VALUE;
    int maxProfit = 0;
    for (int i = 0; i < prices.length; i++) {
        if (prices[i] < minPrice) {
            minPrice = prices[i];
        } else if (prices[i] - minPrice > maxProfit) {
            maxProfit = prices[i] - minPrice;
        }
    }
    return maxProfit;
}

复杂度分析

  • 时间复杂度:O(n),只需要遍历一次。

方法三:动态规划

dp[i]=max{dp[i-1],a[i]}
a[i]代表当天最大利润 =今天的价格 - 之前最低价格

public int maxProfit(int[] prices) {
    int max_profit = 0, min_prices = Integer.MAX_VALUE;
    for (int i = 0; i < prices.length; i++) {
        min_prices = Math.min(min_prices, prices[i]);
        max_profit = Math.max(max_profit, prices[i] - min_prices);
    }
    return max_profit;
}

复杂度分析

  • 时间复杂度:O(n),只需要遍历一次。

延伸

持有一股的情况下

  • 允许买卖无限次。
  • 允许买卖2次。
  • 允许买卖k次。

定义状态

每天都有三种「选择」:买入、卖出、无操作,我们用 buy, sell, rest 表示这三种选择。但问题是,并不是每天都可以任意选择这三种选择的,因为 sell 必须在 buy 之后,buy 必须在 sell 之后。那么 rest 操作还应该分两种状态,一种是 buy 之后的 rest(持有了股票),一种是 sell 之后的 rest(没有持有股票),还有交易次数 k 的限制,就是说你 buy 还只能在 k > 0 的前提下操作
这个问题的「状态」有三个,第一个是天数,第二个是允许交易的最大次数,第三个是当前的持有状态(用 1 表示持有,0 表示没有持有)。然后我们用一个三维数组就可以装下这几种状态的全部组合

dp[i][k][0 or 1]
0 <= i <= n-1, 1 <= k <= K
n 为天数,大 K 为最多交易数

求解状态转移方程

my-logo.png
通过这个图可以很清楚地看到,每种状态(0 和 1)是如何转移而来的

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
              max(   选择 rest  ,           选择 sell      )

解释:今天我没有持有股票,有两种可能:
要么是我昨天就没有持有,然后今天选择 rest,所以我今天还是没有持有;
要么是我昨天持有股票,但是今天我 sell 了,所以我今天没有持有股票了。

dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
              max(   选择 rest  ,           选择 buy         )

解释:今天我持有着股票,有两种可能:
要么我昨天就持有着股票,然后今天选择 rest,所以我今天还持有着股票;
要么我昨天本没有持有,但今天我选择 buy,所以今天我就持有股票了。