LeetCode第3天 | 动态规划 | 20220715

LeetCode第3天 | 动态规划 | 20220715

动态规划

本文章参考了许多他人的笔记,仅供自己学习复习使用。
leetcode官网



不知道是不是因为是“股票”,感觉脑子不太转的来…

【第一题】 121.买卖股票的最佳时机

1.1 读题

在这里插入图片描述

  • 已知:数组prices[0…i], 表示day0-day i 每天的股票价格
  • 条件:i < j时,保证prices[i] <= prices[j]才可以卖出(这里带等号,因为可以同时满足“若无收益则输出0” 的条件)
  • 输出:股票收益最大值

首先想到了遍历并用一个变量记录每轮的最大值,在时间复杂度O(n^2)可以求出答案,见1.2.1,但显然会超时。
再考虑如何一次遍历数组得出答案,见1.2.2.

1.2 解题

1.2.1 超时的暴力求解

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

1.2.2 一次遍历

考虑第i天:如何使第i天卖出时股票收益最大——即,在第i天股票卖出,且在前面第0天到第i-1天中的股票价格最低时买入。所以当考虑第i天的收益时,只需要找到前i-1天中的最低价即可

状态方程maxprofit[i] = price[i] - minprice[i-1]

注意:其中minprice[i-1]并不是指第i-1天的最低价,而是指前面i-1天中的最低价。

官网代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int inf = 1e9;
        int minprice = inf, maxprofit = 0;
        for (int price: prices) {
            maxprofit = max(maxprofit, price - minprice);
            minprice = min(price, minprice);
        }
        return maxprofit;
    }
};


修改成好理解的:首先规定好maxprofit = 0,且minprice = prices[0], 循环从i = 1开始:【注意,及时是i =1开始,maxprofit初始值也不应该是prices[0],因为第0天买第0天卖的收益仍然是0。】

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int minprice = prices[0];
        int maxprofit = 0;

        for(int i =1;i<n;i++){
            maxprofit = max(maxprofit, prices[i] - minprice);
            minprice = min(minprice, prices[i]);
        }
        return maxprofit;
    }
};

这题和昨天1014. 最佳观光组合的思路很像


【第二题】122. 买卖股票的最佳时机 II

2.1 读题

在这里插入图片描述
在这里插入图片描述

  • 已知:数组prices[0…i], 表示day0-day i 每天的股票价格
  • 条件:“你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。”
  • 输出:能获得的最大利润

2.2 解题

参考 liweiwei解答

状态转移:可以先购买,然后在 同一天 出售
在这里插入图片描述
原答主的代码为java,修改成cpp成功通过

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        if(len <2){ // len =0 or 1
            return 0;
        }

        /*
        cash: 持有现金
        hold: 持有股票(若为负数表示持有多少股票,为正数说明前面转的比持股的还多了)
        状态数组
        状态转移:cash -> Hold -> cash -> hold -> cash ->hold -> cash; 每天可以转移,也可以不动,这儿不动的箭头没法画出来
        */
        vector<int>cash(len);
        vector<int>hold(len);// 买入股票后手中剩余的钱
		
		// 一开始无法直接出售。虽然第0天可以出售,但是毫无意义:
		// 买入prices[0]再卖出prices[0]利润为0
        cash[0] = 0;
        // 初始化买入prices[0],持股记对应股票价格的相反数
        hold[0] = - prices[0];

        for(int i = 1; i< len; i++){
            // 以下两行对调也可以
            
            cash[i] = max(cash[i-1], hold[i-1]+prices[i]);
            
            hold[i] = max(hold[i-1], cash[i-1]-prices[i]);
            /*
			若hold[i-1] > cash[i-1]-prices[i],
			*/

        }
        return cash[len-1];
    }
};

手动模拟一边过程理解更清晰。
请添加图片描述

疑问:
a. 如何保证一时间最多只持有一股的?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值