LeetCode动态规划(四)之打家劫舍买卖股票

news/2024/11/15 22:31:06/

文章目录

  • 前言
  • 打家劫舍
    • 1.lc198 打家劫舍
    • 2.lc213 打家劫舍II
    • 3.lc337 打家劫舍 III
  • 买卖股票
    • 0.模板套路
    • 1.lc121 买卖股票的最佳时机
    • 2.lc122 买卖股票的最佳时机II
    • 3.lc714 买卖股票的最佳时机含手续费
    • 4.lc309. 最佳买卖股票时机含冷冻期
    • 5. lc123 买卖股票的最佳时机 III
    • 6. lc188 买卖股票的最佳时机 IV

前言

对于动态规划来说,有两个比较有意思的专题,就是打家劫舍和买卖股票,也可以说是经典问题

打家劫舍

1.lc198 打家劫舍

lc198链接

描述:

如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例:

输入:[2,7,9,3,1]
输出:12

Solution:
dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]
递推公式的精髓在于,站在某一个房子处考虑你是偷还是偷,如果偷,那前一个房子就不能被考虑;如果偷,那金额的最大就来自于偷前一个房屋积累的。

public int rob(int[] nums) {int[] dp = new int[nums.length];if(nums.length==1) return nums[0];dp[0] = nums[0];dp[1] = Math.max(nums[0],nums[1]);for(int i=2;i<nums.length;i++){dp[i] = Math.max(dp[i-2]+nums[i],dp[i-1]); }return dp[nums.length-1];}

2.lc213 打家劫舍II

lc213 链接

描述:
在上一题基础上增加约束 房屋围成一圈
示例:
输入:nums = [2,3,2] 输出:3(不能2+2,因为是相邻的)

Solution:
把这个序列拆成两段,第一段不包括尾元素,第二段不包括首元素

 public int rob(int[] nums) {if(nums.length==1){return nums[0];}int [] dp1 = new int[nums.length];int [] dp2 = new int[nums.length];dp1[0] = nums[0];dp1[1] = nums[0];dp2[1] = nums[1];for(int i =2; i<nums.length; i++){dp1[i] = Math.max(dp1[i-2]+nums[i],dp1[i-1]);dp2[i] = Math.max(dp2[i-2]+nums[i],dp2[i-1]);}return Math.max(dp1[nums.length-2],dp2[nums.length-1]);}

3.lc337 打家劫舍 III

lc337链接

描述:二叉树偷窃
示例:
输入: root = [3,2,3,null,3,null,1] 输出: 7

Solution:

买卖股票

0.模板套路

买卖股票一共有6题,可以用一个统一的框架去做(https://labuladong.github.io)

整个买卖股票涉及的【状态】最多有三个(所以根据题意要不要用三维dp)

  • 第一个是天数
  • 第二个是允许交易的最大次数
  • 第三个是当前的持有状态(可以设 1 表示持有,0 表示没有持有)
dp[i][k][0 or 1] 0 <= i <= n - 1, 1 <= k <= K
n 为天数,大 K 为交易数的上限,01 代表是否持有股票。
此问题共 n × K × 2 种状态,全部穷举就能搞定。
遍历:
for 0 <= i < n:for 1 <= k <= K:for s in {0, 1}:dp[i][k][s] = max(buy, sell, rest)

举个例子:比如说 dp[3][2][1] 的含义就是:今天是第三天,我现在手上持有着股票,至今最多进行 2 次交易
最后要求的答案是:dp[n - 1][K][0](即第n天,交易K次,卖出状态下的利润)

然后状态转移方程分为两步,分别是此时不持有股票的最大利润怎么推导,和此时持有股票的最大利润怎么推导来。

// 今天没有持有= 昨天没有持有+昨天持有(今天卖了,所以利润增加)
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
// 今天持有= 昨天持有+ 昨天没持有(今天买了,利润减少,同时交易次数减1)
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])// base case 情况
dp[0][……][0] = 0 (第一天没持有,利润为0)
dp[0][……][1] = -prices[0] (一开始就持有,所以第一天就买入,所以利润为负)
dp[……][0][0] = 0 (交易次数是0次,即不能交易,所以利润为0//dp[...][0][1] = -infinity

1.lc121 买卖股票的最佳时机

lc121链接

描述:

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

示例:

输入:[7,1,5,3,6,4]  输出:5

Solution:
利用上面的统一框架,这里没有限制交易次数,所以用一个二维dp就可以了

 public int maxProfit (int[] prices) {// write code hereint[][] dp = new int[prices.length][2];// dp初始化dp[0][1] = -prices[0];dp[0][0] = 0;for(int i=1;i<prices.length;i++){// 0表示未持有dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);// 1表示持有(注意这里如果前一天未持有则利润肯定为0)dp[i][1] = Math.max(-prices[i],dp[i-1][1]);}return dp[prices.length-1][0];}}

2.lc122 买卖股票的最佳时机II

lc22链接

相比较上题,不限制交易次数(即k为正无穷)

示例:

输入:prices = [7,1,5,3,6,4]
输出:7(5-1+6-3)

Solution:
按照统一模板,有k这个状态,但是此时的k又是无穷状态(所以k与k-1可以看成一样的,也就是可以不用三维dp)

与上一题相比只需要修改状态转移方程

// 0表示未持有
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
// 1表示持有(这里相比于上题的区别是第i天持有,第i-1天未持有但是可以有利润)
dp[i][1] = Math.max(dp[i-1][0]-prices[i],dp[i-1][1]);

3.lc714 买卖股票的最佳时机含手续费

lc714链接

描述:

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了

示例:
输入:prices = [1, 3, 2, 8, 4, 9], fee = 2
输出:8

Solution:
与上题相似的思路,k依然是无穷,只不过多了个手续费。只需稍微修改状态转移和初始化状态:

 dp[0][1] = -prices[0]-fee;dp[0][0] = 0;for(int i=1;i<prices.length;i++){// 0表示未持有dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);// 1表示持有dp[i][1] = Math.max(dp[i-1][0]-prices[i]-fee,dp[i-1][1]);}

4.lc309. 最佳买卖股票时机含冷冻期

lc309链接

描述:

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

示例:

输入: prices = [1,2,3,0,2]
输出: 3

Solution:
与前两题相比,k依然是无穷,但多了个冷冻期,冷冻期为1天。 所以第 i 天选择 buy 的时候,要从 i-2 的状态转移,而不是 i-1 。

public int maxProfit(int[] prices) {if(prices.length==1) return 0;int[][] dp = new int[prices.length][2];// dp初始化dp[0][1] = -prices[0];dp[0][0] = 0;dp[1][0] = Math.max(dp[0][0],dp[0][1]+prices[1]);dp[1][1] = Math.max(-prices[1],dp[0][1]);for(int i=2;i<prices.length;i++){// 0表示未持有dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);// 1表示持有dp[i][1] = Math.max(dp[i-2][0]-prices[i],dp[i-1][1]);}return dp[prices.length-1][0];
}

5. lc123 买卖股票的最佳时机 III

lc123链接

描述:

你最多可以完成 两笔 交易

示例:

输入:prices = [3,3,5,0,0,3,1,4]
输出:6

Solution1:
k=2的情况,引入3维dp。因为k比较小,可以枚举状态

 public int maxProfit(int[] prices) {int len = prices.length;// dp[i][k][s]int[][][] dp = new int[len][3][2];dp[0][1][0] = 0;dp[0][1][1] = -prices[0];dp[0][2][0] = 0;dp[0][2][1] = -prices[0];for(int i=1;i<len;i++){// 今天没有持有= 昨天没有持有+昨天持有(今天卖了,所以利润增加)// dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])// 今天持有= 昨天持有+ 昨天没持有(今天买了,利润减少,同时交易次数减1)// dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])dp[i][1][0] = Math.max(dp[i-1][1][0],dp[i-1][1][1]+prices[i]);dp[i][1][1] = Math.max(dp[i-1][1][1],-prices[i]);dp[i][2][0] = Math.max(dp[i-1][2][0],dp[i-1][2][1]+prices[i]);dp[i][2][1] = Math.max(dp[i-1][2][1],dp[i-1][1][0]-prices[i]);}return dp[len-1][2][0];}

Solution2:
不仅穷举天数状态,还要枚举交易次数状态。所以两个for循环

在这里插入代码片

6. lc188 买卖股票的最佳时机 IV

lc188链接

至多k笔交易
输入:k = 2, prices = [2,4,1]
输出:2

Solution:
大boss,三种状态都要穷举,参考上面的解法2


http://www.ppmy.cn/news/590960.html

相关文章

电脑上如何进行MP4格式转换成其它格式?

对于MP4格式转换成其它视频格式&#xff0c;简单的理解就是视频格式之间转换的问题&#xff0c;关于视频转换的操作&#xff0c;想必我们都不陌生&#xff0c;生活中有很多视频播放器&#xff0c;但是有的视频明明是正常的却怎么也打不开&#xff0c;原因就在于格式的问题了&am…

diffusion model(二)—— DDIM技术小结

论文地址&#xff1a;Denoising Diffusion Implicit Models github地址&#xff1a;https://github.com/ermongroup/ddim 背景 去噪扩散概率模型 (DDPM1) 在没有对抗训练的情况下实现了高质量的图像生成&#xff0c;但其采样过程依赖马尔可夫假设&#xff0c;需要较多的时间…

英特尔 oneAPI 2023 黑客松大赛:赛道二机器学习:预测淡水质量 实践分享

目录 一、问题描述二、解决方案1、方案简述2、数据分析预处理特征类型处理特征分布分析 3、特征构造4、特征选择过滤法重要性排序 5、模型训练 总结未来工作 一、问题描述 淡水是我们最重要和最稀缺的自然资源之一&#xff0c;仅占地球总水量的 3%。它几乎触及我们日常生活的方…

linux3.4.2内核移植详解(六):基于UVC的USB摄像头内核配置

在menuconfig中进行适当的配置&#xff1a; Device Drivers ---> <*> Multimedia support ---> [*] Video capture adapters---> [*] V4L USBdevices ---> <*> USB Video Class (UVC) [*] UVC input events devicesupport <*> GSPCA based w…

python增删改查csv文件_Python增删改查文件

#!/usr/bin/env python # -*- coding:utf-8 -*- # author:Erik Chan # datetime:2018/12/27 9:29 # software: PyCharm import os # 获取当前文件的父目录文件夹 DIR os.path.dirname(os.path.abspath(__file__)) cwd os.getcwd() #获取当前目录即dir目录下 print(cwd) # 创建…

在树莓派上使用MJPG-Streamer实现网络监控

1,首先将usb摄像头连接在树莓派上,为了找到树莓派上的摄像头设备我们需要在查看树莓派上所有的USB设备,因为这个摄像头通过 USB与树莓派连接。 列出所有的USB设备: Lsusb 2,安装 hwinfo(查看硬件信息命令) sudo apt-get install hwinfo 3,查看usb设备的具体信息,…

基于Matlab软件的视觉导航系统的仿真

对视觉导航系统进行处理&#xff0c;主要包括三部分&#xff1a; 1.图像处理&#xff08;获取双目视觉图像&#xff0c;标定相机参数&#xff0c;对图像进行矫正&#xff09; 2.三维重建&#xff08;双目摄像头获取图片&#xff0c;通过立体匹配建立两个图像之间的关系&#xf…

基于LINUX下的USB摄像头监控系统

一&#xff0e;摄像头的选择 当摄像头插在树莓派上&#xff0c;有的摄像头由于没有驱动&#xff0c;所以无法正常工作&#xff0c;而市面上的USB摄像头都是免驱的&#xff0c;所以选择一个免驱的摄像头会给项目减去很多麻烦&#xff0c;这次选择的是一个谷客的USB摄像头。 二&a…