LeetCode第 122 题:买股票的最佳时机II(C++)

122. 买卖股票的最佳时机 II - 力扣(LeetCode)
在这里插入图片描述

股票系列:
LeetCode第 121 题:买股票的最佳时机(C++)_zj-CSDN博客
LeetCode第 122 题:买股票的最佳时机II(C++)_zj-CSDN博客
LeetCode第 123 题:买股票的最佳时机III(C++)_zj-CSDN博客
LeetCode第 188 题:买股票的最佳时机IV(C++)_zj-CSDN博客
LeetCode第 309 题:最佳买卖股票时机含冷冻期(C++)_zj-CSDN博客
LeetCode第 714 题:买卖股票的最佳时机含手续费(C++)_zj-CSDN博客

因为上一题dp,这一题一直想怎么dp,然后就卡壳了。。。

其实就一张图的事(来自官方题解:买卖股票的最佳时机 II - 买卖股票的最佳时机 II - 力扣(LeetCode)):

在这里插入图片描述
要想收益最大化,只要碰到波峰就卖,收益就是波峰减去波谷:

Total Profit = ∑ i ( height ( peak i ) − height ( valley i ) ) \text {Total Profit}=\sum_{i}\left(\text {height}\left(\text {peak}_{i}\right)-\text {height}\left(\text {valley}_{i}\right)\right) Total Profit=i(height(peaki)height(valleyi))

其实这有点像贪心的思路

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int vally = prices[0], peak = prices[0], res = 0;
        int i = 0;
        while(i < n-1){//
            while(i < n-1 && prices[i] >= prices[i+1]) ++i;
            vally = prices[i];
            while(i < n-1 && prices[i] <= prices[i+1]) ++i;
            peak = prices[i];//如果一直没有找到峰或者谷,那最后vally,peak均等于最后一个元素
            res += peak - vally;
        }
        return res;
    }
};

其实转化一下,当某个元素比它的前一个元素要大的时候,就可以累加差值,都不用考虑波峰波谷:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int res = 0;
        for(int i = 1; i < n; ++i){
            if(prices[i] > prices[i-1]) res += prices[i] - prices[i-1];
        }
        return res;
    }
};

至于这样为什么能行,可以看一下:暴力搜索、贪心算法、动态规划 - 买卖股票的最佳时机 II - 力扣(LeetCode)的方法二的解释。

动态规划

这个题动态规划还是可以用的,之前想不出状态怎么转移,看了下面的题解之后还是明白了。

注意题目给的数组是一只股票在不同日期的价格

状态定义

每一天可能有三种动作:买,卖,什么都不做

二维dp:第一维表示日期(第几天),第二维表示(这一天结束之前)是否持有股票(1:有,0:无),数组值表示收益:

vector<vector<int>> dp(n, vector<int>(2, 0));
状态转移

第一种情况,当天(结束之前)手上没有股票,走到这一步有两种可能:

  • 前一天手上就没有股票,今天什么都不做
  • 前一天手上有股票,今天进行卖出(获得收益)

第二种情况,当天(结束之前)手上有股票,走到这一步也有两种可能:

  • 前一天手上就有股票,今天什么都不做
  • 前一天手上没有股票,今天进行了买入(花掉一笔钱)

我们要使得收益最大,所以状态转移的时候在两种情况中取收益较大者,有:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
边界状态

第i天的状态只能由第i-1天的状态推导而来,那么i = 0(第一天)的状态定义为:

dp[0][0] = 0; //第一天没有股票,没有任何动作,收益为0
dp[0][1] = 0 - prices[0]; //第一天(结束之前)有股票,说明今天进行了买入,收益为负(花掉一笔钱)
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if(n < 2) return 0;
        //第一维表示日期,第二维表示是否持有股票(1:有,0:无),数组值表示收益
        vector<vector<int>> dp(n, vector<int>(2, 0));
        dp[0][0] = 0; //第一天没有股票,没买没卖,收益为0
        dp[0][1] = 0 - prices[0]; //第一天有股票,说明买入了,收益为负(花掉一笔钱)
        for(int i = 1; i < n; ++i){
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);//第i天没有股票
            dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1]);//第i天持有股票
        }
        //return max(dp[n-1][0], dp[n-1][1]);要想收益最大,最后一天肯定不会进行买入,所以dp[n-1][0]肯定更大
        return dp[n-1][0];
    }
};

这道题的dp其实不难写,但是很难解释,这位同学解释的很好:股票交易系列:贪心思想和动态规划 - 买卖股票的最佳时机 II - 力扣(LeetCode)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值