【C++编程能力提升】

代码随想录训练营Day49 | Leetcode 121、122

一、121 买卖股票的最佳时机

题目链接:121 买卖股票的最佳时机

核心:要求只买卖一次,使用贪心求解是较为简单的,只需遍历所有元素后确定左边界(min)和最大利润(max)即可。
如果使用动态规划求解,dp数组的定义是第一步,其次需要确定递推公式。
第一,dp[i][0]和dp[i][1]分别表示第i天持有/不持有股票所得的现金;
第二,考虑dp[i][0]的递推公式,第i天持有股票可能存在两种情况,其一第i-1天已经持有,那么第i天只是延续第i-1天的状态;其二第i天买入(且是第一次买入也是唯一一次买入,因为只允许买卖一次);同理考虑dp[i][1]的递推公式,第i天不持有股票也可能存在两种情况,其一第i-1天已经不持有,那么第i天只是延续第i-1天的状态;其二第i天卖出,那么隐含着第i-1天是持有股票的。并且dp数组的两个状态都表示当前所拥有的现金,因此都需要取其max。
第三,最后一天手中不持有股票时所拥有的现金就是最大利润值,而不是手中持有股票时是最大利润值(简单地理解就是只有把股票卖出去才能有利润)。

    int maxProfit(vector<int>& prices) {
        //动态规划:dp[i][0]&dp[i][1]分别表示第i天持有/不持有股票所得最大现金
        if(prices.size()==0)    return 0;
        vector<vector<int>> dp(prices.size(),vector<int>(2));
        dp[0][0]=-prices[0];    //第0天(对应数组下标)持有说明第0天买入股票
        dp[0][1]=0;             //第0天不持有说明未买入股票,仍保持为0
        for(int i=1;i<prices.size();++i)
        {//遍历所有元素,分析第i天是否持有股票两种状态下所拥有的最大现金
            dp[i][0]=max(dp[i-1][0],-prices[i]); //要么是前一天已持有,要么是当天买入(第一次)
            dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]);//要么是前一天不持有,要么是当天卖出
        }
        return dp[prices.size()-1][1];//最终一定是手中不持有股票的情况下利润最大

        /*
        //贪心:左边取min,右边取max
        int low=INT_MAX;    //min初始化为最大值
        int res=0;          //最大利润初始化为0
        for(int i=0;i<prices.size();++i)
        {//遍历所有元素,遍历结束时可确定最小值和利润最大值
            low=min(low,prices[i]);
            res=max(res,prices[i]-low);
        }
        return res;
        */
    }

二、122 买卖股票的最佳时机II

题目链接:122 买卖股票的最佳时机II

核心:允许多次买卖股票求解利润最大值,贪心的思想是不太容易想到的,反而动态规划比较简单,只需进行一点扩展即可。
1、贪心法:
计算相邻元素的正值累加即为所获取的最大利润,因为不限制买卖次数,只要求利润最大,那么每一次买卖时利润为正就能满足所有元素参与买卖时的利润最大(此处的参与并不代表一定会买卖,只有在后一天与当天利润差值为正时才参与买卖)。

2、动态规划:
同样定义dp数组:dp[i][0]和dp[i][1]分别表示第i天持有/不持有股票所拥有的现金
121 买卖股票的最佳时机的区别是dp[i][0]的递推公式,dp[i][0]表示第i天持有股票所得的现金,要么是第i-1天就已经持有股票,那么延续第i-1天的状态;要么是第i天买入,此时并非第一次买入,因此需要考虑第i-1天不持有的情况。

    int maxProfit(vector<int>& prices) {
        //动态规划:dp[i][0]&dp[i][1]分别表示第i天持有/不持有股票的所得现金
        int len=prices.size();
        if(len==0)  return 0;
        vector<vector<int>> dp(len,vector<int>(2));
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        for(int i=1;i<len;++i)
        {
            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]);
        }
        return dp[len-1][1];

        /*
        //贪心算法:只统计相邻两天的利润为正数的情况
        int res=0;  
        for(int i=1;i<prices.size();++i)
        {//遍历股票数组,从第二个元素开始,计算与前一个元素的利润,并取其正数
            res+=max(prices[i]-prices[i-1],0);
        }
        return res;
        */
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值