本文最后更新于81 天前,其中的信息可能已经过时,如有错误请发送邮件到3091169959@qq.com
一、题目描述
给你一个整数数组 prices
,其中 prices[i]
表示某支股票第 i
天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4] 输出:7 解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3。 最大总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。 最大总利润为 4 。
示例 3:
输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0。
提示:
1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104
二、题目分析
与上一道买卖股票的不同,这次允许多次买卖,但是手上的股票量做了限制,只能持有一个股票,所以要买入股票之前必须清空手中的股票。那我要找到最大利润,那应该用动态规划或者贪心的方法。动态规划主要是基于模拟交易的具体过程,要获得当前的最大利益,主要取决于两个状态,持有股票时的最大利润和不持有股票时的最大利润,所以我们遍历每一天的价格,并根据前一天的状态更新当前天的状态。
状态定义:
dp[i][0]
表示第i
天不持有股票时的最大利润。dp[i][1]
表示第i
天持有股票时的最大利润。
状态转移方程:
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
:第i
天不持有股票的最大利润可以由前一天不持有股票或前一天持有股票并在今天卖出两种情况中的较大值得出。dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
:第i
天持有股票的最大利润可以由前一天持有股票或前一天不持有股票并在今天买入两种情况中的较大值得出。
初始条件:
dp[0][0] = 0
:第一天不持有股票,利润为0。dp[0][1] = -prices[0]
:第一天持有股票,利润为负的当天股价。
三、代码实现
public class P122 {
static class Solution {
public int maxProfit(int[] prices) {
int maxProfit = 0;
int n = prices.length;
//[n][0]表示当天手上无股票,[n][1]表示当天手上有股票
int[][] dp = new int[n][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for(int i = 1 ; i < n ; i++) {
//前一天的利润或者卖掉今天后的利润
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
//前一天的利润扣掉买今天的成本或者原本手上有股票的利润
dp[i][1] = Math.max(dp[i-1][0] - prices[i],dp[i-1][1]);
}
//最后一天手上应没有股票
return dp[n-1][0];
}
}
public static void main(String[] args) {
int[] prices = {7,1,5,3,6,4};
Solution solution = new Solution();
System.out.println(solution.maxProfit(prices));
}
}
四、思考
刚刚的动态规划更多的是模拟整个过程,其实对于只需要结果的题目,最大利润只要求出每个价格上行的累加和,可以参考下面的折线图,最大利润就是每一段上行线段的累加。每次都选取有利润的交易,就是贪心的体现。
- 遍历价格数组,从第二天开始。
- 如果当天的价格高于前一天的价格,则将差值加入总利润。
代码实现
class Solution {
public int maxProfit(int[] prices) {
int maxProfit = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i-1]) {
maxProfit += prices[i] - prices[i-1];
}
}
return maxProfit;
}
}
五、总结
复杂度分析
- 动态规划:
- 时间复杂度:O(n),遍历数组一次。
- 空间复杂度:O(n),使用二维数组存储状态。
- 贪心算法:
- 时间复杂度:O(n),遍历数组一次。
- 空间复杂度:O(1),仅使用常数空间。
两种方法各有优劣,动态规划方法更通用,可以处理更复杂的问题变种,而贪心算法在时间和空间上更高效。根据具体需求选择合适的解法。