leetcode 121. 买卖股票的最佳时机 (贪心 + 动规 + 双指针

贪心的思路:

得到最小值,再挨个用数组中的值减去最小值,最终值取一个最大的

class Solution {
public:
    int maxProfit(vector<int>& prices) {

       // 贪心: 找到最小的,然后逐个减掉最小的,取最终值为最大的为 res 
       int low = INT_MAX;
       int res = 0;
       for(int i = 0; i < prices.size(); i++)
       {
           low = min(prices[i], low);
           res = max(res, prices[i] - low);
       }

       return res;
    }
};

动规的思路:

现在觉得做动规的关键点就是找出,当前的状态是否与之前的状态有关,也就是说:当前一般会有两种状态,具体哪一种为最优,需要依靠之前的状态及逆行推导。

比如说本题

当天有两种状态:持有股票,和不持有股票。(这里没有使用买入、卖出作为含义是因为:单纯的买入,卖出,无法表示出更确切的状态。比如说前一天买入,后一天不进行任何操作,那么这个不进行操作的状态就无法表示了

1. dp数组的表示含义

        这里使用二维数组的原因是因为,一个维度表示天数,一个维度表示股票的状态

        dp [ i ] [ 0 ] 表示第 i 天持有股票,值为:所获得的利润

        dp [ i ] [ 1 ] 表示第 i 天不持有股票, 值为:所获得的利润

2. 递推公式

持有股票:

        第 i 天买入的: -price[ i ]

        第 i 天之前就买入了:dp[ i  - 1][ 0 ]

两者取最大值

不持有股票:

        第 i 天卖出: dp [ i - 1][ 0 ] + price[ i ]

        第 i 天之前就卖出了: dp [ i - 1 ][ 1 ]

两者取最大值

3. 初始化

dp[ 0 ] [ 0 ] =  - price[ 0 ]

dp[ 0 ] [ 1 ] = 0

4. 遍历顺序,从前向后

注意:

这里最终求的其实就是

dp [ price.size() - 1] [ 1 ]

因为最后一定是手里没有股票的利润会更大

class Solution {
public:
    int maxProfit(vector<int>& prices) {

        vector<vector<int>> dp(prices.size(), vector<int>(2));
        
        // 初始化
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        
        // 遍历 + 递推
        for(int i = 1; i < prices.size(); 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];
    }
};

3. 双指针

一个指向前一天,一个指向当天,这样就保证只会在买入后卖出,找出利润最大的

class Solution {
public:
    int maxProfit(vector<int>& prices) {
       // 双指针

       int left = 0 ,right = 1;
       int res = 0;
       for(; right < prices.size();)
       {
           int x = prices[right] - prices[left];
           if(x > 0)   // 不断移动  right,继续寻找更大的利润
           {
               res = max(res, x);
               right++;
           } 
           else   //如果利润为负数 让 left 尽可能小,然后移动一次right 
           {
               left = right; // 注意这里是直接移动到right , 让 left 处于尽可能小的位置
               right++;
           } 
       }
       return res;
    }
};

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值