当前位置: 首页 > article >正文

算法刷题打卡042 | 动态规划10

这一天的题目内容开启了买卖股票最佳时机的专题,两道最基础也是最经典的题目复习回顾买卖股票相关的动态规划问题。

LeetCode 121 买卖股票的最佳时机

题目链接:121. 买卖股票的最佳时机 - 力扣(Leetcode)

买卖股票的第一个版本是只交易两次,分别是买入以及在买入之后的卖出。由于只有正利润才符合题目预期结果,当股票价格呈现非递增变化时,买卖股票无法获得收益(甚至有可能亏损),因此可以贪心地找左端最小值及其对应的右端最大值,取其中最大的差值。具体做法是遍历每天的股票价格,不断更新左端的最小值,同时计算当前价格与最小值的差值,更新结果:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 贪心写法
        minprice = prices[0]
        maxprofit = 0
        for i in range(1, len(prices)):
            maxprofit = max(maxprofit, prices[i]-minprice)
            minprice = min(minprice, prices[i])
        return maxprofit

 而用动态规划分析题目,按时间顺序,每一天的最大利润和前一天的状态息息相关,存在一个状态推导的过程。具体状态的定义比较讲究对问题的理解,比如对于股票的买卖,有持有和不持有两种状态,他们都能通过保持原有状态直接继承前一天的状态,也可以通过买卖操作更新,并且按题目要求取二者的最大值:

#include<algorithm>
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        // dp[i][0] 持有;dp[i][1] 不持有
        vector<vector<int>> dp(n, vector<int>(2));
        // 初始化
        dp[0][0] = -prices[0];
        for(int i=1; i < n; i++){
            // dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[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 max(0, dp[n-1][1]);  // 最终要求的是最后一天不持有股票的状态(如果为负利润返回0)
    }
};

 要注意本题只能进行一次买入卖出,因此dp[i][0]更新时,当天买入一定是-prices[i],而不是像注释的那样从前一天不持有的状态减去prices[i],因为如果前一天属于已经交易完的不持有状态,在它的基础上买入就违反了买卖规则。实际上注释写法应该是属于不限制买卖次数的情境。

状态推导过程中只依赖前一天的状态,因此空间复杂度可进一步优化,不再赘述。

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

题目链接:122. 买卖股票的最佳时机 II - 力扣(Leetcode)

这一题其实就是在上一题的基础上不限制买卖次数,题目的“最多只能持有一股股票”,其实就是要求每次买入前必须保证手头没有持有股票,也就是下一次买入前必须经过卖出操作,沿用上一题的代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        // dp[i][0] 持有;dp[i][1] 不持有
        vector<vector<int>> dp(n, vector<int>(2));
        // 初始化
        dp[0][0] = -prices[0];
        for(int i=1; i < n; i++){
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[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 max(0, dp[n-1][1]);  // 最终要求的是最后一天不持有股票的状态(如果为负利润返回0)
    }
};

贪心的解法就是遍历找所有递增区间,在每个递增区间的起点和终点分别进行买入和卖出,可以保证利润最大化:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        if n < 2:
            return 0  # 无法进行交易
        # idx, total = 0, 0
        # # 方法是找上升区间
        # while idx < n:
        #     while idx < n - 1 and prices[idx] > prices[idx + 1]:
        #         idx += 1
        #     min_price = prices[idx]
        #     while idx < n - 1 and prices[idx] < prices[idx + 1]:
        #         idx += 1
        #     total += prices[idx] - min_price
        #     idx += 1
        
        # return total
        total = 0
        for i in range(1, n):
            total += max(0, prices[i] - prices[i-1])
        return total

http://www.kler.cn/a/7382.html

相关文章:

  • 动手学深度学习73 课程总结和进阶学习
  • L11.【LeetCode笔记】有效的括号
  • 学习threejs,使用第一视角控制器FirstPersonControls控制相机
  • Jav项目实战II基于微信小程序的助农扶贫的设计与实现(开发文档+数据库+源码)
  • TypeORM在Node.js中的高级应用
  • 大学语文教材电子版(第十一版)教学用书PDF及课件
  • vue3之shallowRef以及使用对element-plus table的优化尝试
  • Scrapy-应对反爬虫机制
  • 【vscode】检查到已经改正的错误,没有错误却检查到有错误
  • js跨域与解决
  • [GXYCTF2019]BabyUpload
  • 摸鱼也可以效率翻倍:Python 统计 gitlab 代码量,定量统计发给领导
  • Python3 os.isatty() 方法、Python3 os.dup2() 方法
  • Hadoop基础介绍
  • JetpackCompose从入门到实战学习笔记13——Compose中实现简单瀑布流
  • 基于html+css的内容旋转
  • Solon v2.2.7 发布,支持 Java 20
  • MLSkin 5.3 for delphi Crack
  • 约瑟夫问题
  • 【redis】redis分布式锁
  • 镜头光学指标介绍----清晰度SFR
  • 【从零开始学习 UVM】10.2、UVM TLM —— UVM TLM Blocking Put Port
  • 【CSAPP】进程 | 上下文切换 | 用户视角下的并发进程
  • 流量整形(GTS和LR)
  • 蓝桥杯之单片机学习(终)——关于之前文章的错误及更正(附:第十四届蓝桥杯单片机赛题)
  • L2-040 哲哲打游戏 简单模拟