力扣第121题-买卖股票的最佳时机
2026.8.6

1.因为只买卖一次,所以很容易想到使用遍历一遍数组的贪心算法,遍历过程中更新遇到的最小值,并不断更新利润最大值。完整代码如下:
cpp
1. int maxProfit(int* prices, int pricesSize) {
2. // low 记录遍历到当前为止的历史最低股价
3. int low = INT_MAX;
4. // res 记录最大利润,初始为0(不交易利润为0)
5. int res = 0;
6. for (int i = 0; i < pricesSize; i++){
7. // 更新最低买入价格
8. low = fmin(low, prices[i]);
9. // 当天卖出,更新最大利润
10. res = fmax(res, prices[i] - low);
11. }
12. return res;
13. }
该算法时间复杂度为O(n),空间复杂度为O(1)。
2026.8.7
1.本题也可以使用动态规划来解决。当天的状态只有两种:持有股票和未持有股票,所以可以设置一个二维数组dppricesSize2,dpi0代表第i天持有股票的最大现金,dpi1代表第i未持有股票的最大现金。初始现金为0,买入股票后现金变为-pricesi。
2.分类讨论来推导出递推公式:
(1)持有股票。又分为两种情况:之前买入和今天买入,对应的金额分别为dpi - 10和-pricesi,则递推公式为dpi0 = fmax(dpi - 10, -pricesi)。
(2)未持有股票。又分为两种情况:之前就没有和今天卖出,对应金额分别为dpi - 11和dpi - 10 + pricesi,则递推公式为dpi1 = fmax(dpi - 11, dpi - 10 + pricesi)。
3.由于最后卖出股票(即未持有股票)的收益一定大于持有股票,所以最后返回结果一定为dppricesSize -- 11。
4.基于以上思想,可写出完整代码如下:
cpp
1. int maxProfit(int* prices, int pricesSize) {
2. // dp[i][0]:第i天持有股票的最大利润
3. // dp[i][1]:第i天不持有股票的最大利润
4. int dp[pricesSize][2];
5.
6. // 第0天持有:只能当天买入,利润为 -股价
7. dp[0][0] = -prices[0];
8. // 第0天不持有:无操作,利润0
9. dp[0][1] = 0;
10.
11. for (int i = 1; i < pricesSize; i++){
12. // 今天持有两种可能:之前就持有 / 今天刚买入
13. dp[i][0] = fmax(dp[i - 1][0], -prices[i]);
14. // 今天不持有两种可能:之前就不持有 / 今天卖出昨天持有的
15. dp[i][1] = fmax(dp[i - 1][1], dp[i - 1][0] + prices[i]);
16. }
17.
18. // 最后一天一定不持有股票利润最大(持有一定亏钱)
19. return dp[pricesSize - 1][1];
20. }
该算法时间复杂度和空间复杂度均为O(n)。
5.发现递推公式实际上只关心前一项,所以将dp数组的大小减小为dp22来节省空间。完整代码如下:
cpp
1. int maxProfit(int* prices, int pricesSize) {
2. // 滚动dp数组,dp[0]代表前一天状态,dp[1]代表当天状态
3. // dp[x][0]:持有股票最大利润
4. // dp[x][1]:不持有股票最大利润
5. int dp[2][2];
6.
7. // 初始化第0天(第一天)
8. dp[0][0] = -prices[0]; // 当天买入,持有股票
9. dp[0][1] = 0; // 不操作,无股票
10.
11. // 从第二天开始遍历
12. for (int i = 1; i < pricesSize; i++){
13. // 当天持有:昨天就持有 | 今天第一次买入
14. dp[1][0] = fmax(dp[0][0], -prices[i]);
15. // 当天不持有:昨天就无股票 | 昨天持有今天卖出
16. dp[1][1] = fmax(dp[0][1], dp[0][0] + prices[i]);
17. // 更新前一天状态为今天,供下一轮循环使用
18. dp[0][0] = dp[1][0];
19. dp[0][1] = dp[1][1];
20. }
21.
22. // 最后一天不持有股票为答案
23. return dp[0][1];
24. }
该算法时间复杂度为O(n),空间复杂度为O(1)。因为每次for循环都会将dp1的值赋给dp0,最后返回的应选择dp01,以防数组长度只有1而导致dp11是垃圾值。
力扣第122题-买卖股票的最佳时机Ⅱ
2026.7.31

1.为了利益最大化,将股票的每日价格看成一个折线图,在低点买入高位卖出就一定能赚钱,实际上就是寻找数组的极值点。使用贪心算法,完整代码如下:
cpp
1. int maxProfit(int* prices, int pricesSize) {
2. // 只有一天股价,无法完成买卖,利润为0
3. if (pricesSize == 1) return 0;
4.
5. // res 累计总利润
6. int res = 0;
7. // buy 记录买入价格,-1代表当前无持仓
8. int buy = -1;
9. // 从第二天股价开始遍历
10. for (int i = 1; i < pricesSize; i++){
11. // 当前无持仓,且当天股价高于前一天,在前一天买入
12. if (buy == -1 && prices[i] > prices[i - 1]){
13. buy = prices[i - 1];
14. }
15. // 当前持有股票
16. if (buy >= 0){
17. // 当天股价低于前一天,前一天卖出,结算利润,清空持仓
18. if (prices[i] < prices[i - 1]){
19. res += prices[i - 1] - buy;
20. buy = -1;
21. } else if (i == pricesSize - 1){
22. // 遍历到最后一天仍持有股票,当天卖出结算利润
23. res += prices[i] - buy;
24. buy = -1;
25. }
26. }
27. }
28.
29. return res;
30. }
该算法时间复杂度为O(n),空间复杂度为O(1)。
2.官方的贪心算法代码写的极其简单,如果第二天比第一天的股票价格贵就买入并卖出。因为题目上强调了可以当天同时买入与卖出,行为上复杂化且等价于寻找波峰波谷,但代码就会变得非常简单:
cpp
1. int maxProfit(int* prices, int pricesSize) {
2. // res 存放累计的最大利润
3. int res = 0;
4. // 只有一天价格,无法进行买卖,利润为0
5. if (pricesSize == 1) return 0;
6. // 从第二天开始遍历所有价格
7. for (int i = 1; i < pricesSize; i++){
8. // 相邻两天差价为正就累加利润,差价为0或负数不加
9. res += fmax(0, prices[i] - prices[i - 1]);
10. }
11.
12. return res;
13. }
3.官方答案还有动态规划算法,看起来比贪心算法要复杂,当下就不再尝试了。
2026.8.7
1.本题相比于力扣第121题-买卖股票的最佳时机,唯一的区别就在于本题能无限次买卖,所以递推公式上有一定区别,主要体现在"当天持有股票"部分,递推公式从dp10 = fmax(dp00, -pricesi)变为了dp10 = fmax(dp00, dp01 - pricesi)。121题只允许买卖一次,如果当天购买股票就说明之前的现金一定是0,所以最后的金额为-pricesi;122题允许买卖多次,之前未持有股票时的现金就应该是dp01 - pricesi。
2.基于以上思想,可写出完整代码如下:
cpp
1. int maxProfit(int* prices, int pricesSize) {
2. // 滚动DP数组,dp[0]代表前一天状态,dp[1]代表当日状态
3. // dp[x][0]:持有股票最大利润;dp[x][1]:不持有股票最大利润
4. int dp[2][2];
5. // 第一天:持股则买入股票,利润-股价;不持股无操作利润0
6. dp[0][0] = -prices[0];
7. dp[0][1] = 0;
8.
9. for (int i = 1; i < pricesSize; i++){
10. // 今日持股:之前就持有 / 昨天空仓今天买入(允许多次买卖)
11. dp[1][0] = fmax(dp[0][0], dp[0][1] - prices[i]);
12. // 今日空仓:之前就空仓 / 昨天持股今天卖出
13. dp[1][1] = fmax(dp[0][1], dp[0][0] + prices[i]);
14. // 更新前一天状态为当天结果,供下一轮循环使用
15. dp[0][0] = dp[1][0];
16. dp[0][1] = dp[1][1];
17. }
18. // 最后一天一定不持有股票收益最大,返回结果
19. return dp[0][1];
20. }
该算法时间复杂度为O(n),空间复杂度为O(1)。