代码随想录算法训练营Day49|121. 买卖股票的最佳时机、122.买卖股票的最佳时机II

本文介绍了如何通过暴力解法、贪心算法以及动态规划解决买卖股票的最佳时机问题,包括具体的方法、代码实现和空间优化。
摘要由CSDN通过智能技术生成

目录

121. 买卖股票的最佳时机

方法一:暴力解法 

方法二:贪心

方法三:动态规划

算法实现

122.买卖股票的最佳时机II

前言

思路

算法实现

总结:


121. 买卖股票的最佳时机

题目链接

文章链接

方法一:暴力解法 

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

         暴力解法的思路较为简单,但是提交超时了;

方法二:贪心

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int low = INT_MAX;
        int result = 0;
        for (int i = 0; i < prices.size(); i++) {
            low = min(low, prices[i]);
            // 可以保证最大值一定在最小值右侧
            result = max(result, prices[i] - low);
        }
        return result;
    }
};

        贪心的思路,股票只买卖一次,取左值最小值,取右值最大值,得到的差值为最大利润。

方法三:动态规划

        利用动规五部曲进行分析:

1.确定dp数组及其下标含义:

        dp[i][0]表示第i天持有股票所拥有的最大现金,一开始现金是0,那么加入第i天买入股票现金就是 -prices[i], 是一个负数。(此处的持有不是指当天买入,可能是前面几天买入的股票);

        dp[i][1]表示第i天不持有股票所拥有的最大现金;

2.确定递推公式:

        如果第i天持有股票即dp[i][0], 那么可以由两个可能来源

  • 第i - 1天就持有股票,没有卖出,此时dp[i][0] = dp[i - 1][0];
  • 第i - 1天没有持有股票,而是在第i天买入,此时dp[i][0] = -prices[i]

        那么dp[i] 应该选择两种情况中的最大值:dp[i][0] = max(dp[i - 1][0],  -prices[i]);

        如果第i天未持有股票即dp[i][1],同样可能有两个来源:

  • 第i - 1天就未持有股票即dp[i - 1][1]:dp[i][1] = dp[i - 1][1];
  • 第i - 1天还持有股票,在第i天卖出:dp[i][1] = dp[i - 1][0] + prices[i];

        dp[i]依然是取两种情况中的最大值:dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]).

3.dp数组初始化:

        一开始现金是0,在第一天买入股票(持有股票)现金就是-prices[0],即dp[0][0] = -prices[0],第一天未持有股票所拥有的现金就是0,即dp[0][1] = 0;

4.确定遍历顺序:

        从递推公式可以看出dp[i]都是由dp[i - 1]推导出来的,那么一定是从前向后遍历。

5.打印dp数组:

        以示例1,输入:[7,1,5,3,6,4]为例,dp数组状态如下:

        

        dp[5][1]就是最终结果,因为同一天不持有股票时的钱一定比持有股票时的钱多。

算法实现
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        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], -prices[i]);
            dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
        }
        return dp[len - 1][1];
    }
};

        从递推公式可以看出,dp[i]只是依赖于dp[i - 1]的状态,可以对以上算法进行优化,使用滚动数组来节省空间。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>> dp(2, vector<int>(2));
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; i++) {
            dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]);
            dp[i % 2][1] = max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] + prices[i]);
        }
        return dp[(len - 1) % 2][1];
    }
};

122.买卖股票的最佳时机II

题目链接

文章链接

前言

         前一题买卖股票问题只能买卖一次股票,而本题没有一次的限制,虽然每次最多只能仍然只能持有一张股票,但是可以多次买入卖出股票。

思路

        本题与上一题的不同主要在于推导dp[i][0]时,如果第i天持有股票,第一种情况同样是第i - 1天就持有了股票,dp[i][0] = dp[i - 1][0];而第二种情况则是第i - 1天没有持有股票,在第i天购入股票,此时不再是0 - prices[i],因为当前的现金不一定是0,前面可能已经经过了好几次的股票买入和卖出操作,因此此时的dp[i][0] = dp[i - 1][1] + prices[i];

        未持有股票的情况dp[i][1]与上题相同,依然是dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i])。

算法实现

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        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];
    }
};

        同样也可以利用滚动数组进行优化,代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>> dp(2, vector<int>(2));
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; i++) {
            dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]);
            dp[i % 2][1] = max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] + prices[i]);
        }
        return dp[(len - 1)% 2][1];
    }
};

总结:

        今天学了买卖股票类的问题,初步简单掌握。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值