动态规划(二)

上一篇博客讲解了动态规划的定义,这一篇博客主要通过Leetcode上的实例来讲解一下我对动态规划的理解。

  1. 剑指 Offer 63. 股票的最大利润
  2. 122. 买卖股票的最佳时机 II
  3. 123. 买卖股票的最佳时机 III
  4. 188. 买卖股票的最佳时机 IV
  5. 309. 最佳买卖股票时机含冷冻期
  6. 714. 买卖股票的最佳时机含手续费

1. 股票的最大利润

在这里插入图片描述
对于千篇一律的解题思路我就不再赘述了(直接上图)!
在这里插入图片描述
在这里插入图片描述

通过这个实例请你先体会并总结一下动态规划的核心思想! 是不是觉得自己又行了,继续看下一题!

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

在这里插入图片描述
对于千篇一律的解题思路我就不再赘述了(直接上图)!
在这里插入图片描述

	// 0:持有现金
	// 1:持有股票
	// 状态转移:0101010
	// 这两行调换顺序也是可以的
	dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
	dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
	
	// 说明:
	//    因为不限制交易次数,除了最后一天,每一天的状态可能不变化,也可能转移;
	//    写代码的时候,可以不用对最后一天单独处理,输出最后一天,状态为 0 的时候的值即可。

在这里插入图片描述


接下来是这篇博客的核心,主要讲解一下通过这个实例我对动态规划的理解!

  1. 什么情况下使用动态规划?问题中前 i 天能够获得的最大利润不仅仅是由当天决定,而是与前 i-1 天有关。注意这是应用动态规划的决定性标志。而 前 i-1 天又由第 i -1 天与前 i-2 天有关。拆开来理解,前 i 天由 第 1,2,…,i-1,i 天所有情况决定,前 i -1 天由 第 1,2,…,i-2,i-1 天所有情况决定。依次类推,前 3 天由第 1,2,3 天共同决定。
    在这里插入图片描述
    这就是前面所说的动态规划应用于子问题重叠的情况,动态规划就可以很好地解决这种状态重复的问题。
  2. 如何刻画最优解的结构特征?即寻找状态转移方程。问题中前 i 天能够获得的最大利润不仅仅是由当天决定,而是与前 i-1 天有关。 如果你知道该问题需要使用动态规划解决,那么你也必定知道这句话的大意。但是究竟如何去寻找状态转移方程呢?注意:动态规划 dp[i] 研究的是前 i 天能够获得的最大利润,是前 i 天的最优解,是一系列子问题的最优解组成,因此必然是以递归的形式刻画这种结构特征。最简单形式的递归为 x = fun(x)。

回到本题
前 i 天能够获得的最大利润与前 i-1 天的 现存余额 与 持有股票 有关(因为允许多次买卖,可能已经买卖过一次了,因此存在余额与持有股票说法)。所以本题难点在于与过去两个状态有关。
假设cash为现存余额,hold为持有股票,目的是希望现存金额最大,所以在考虑前 i 天的现存余额时,必然是考虑今天的股票是该买还是该卖,如何衡量该买还是该卖?拿前 i-1 天的现存余额与卖掉这只股票相比取其较大值。( 有同学会问,为什么不拿卖掉股票与不卖掉股票相比,而是拿其与现存金额相比? 其实选择现存金额就是表示不卖掉该只股票,而选择卖掉股票就表示买了前面某一天的股票,当然今天这一只是否买入是由后面某天股票价格决定。说实话,靠文字叙述理解起来确实有点难>_< )。于是有:
cash[i] = max(cash[i - 1], hold[i - 1] + prices[i]); // 这里取最大值是希望现存金额较大,即在高价时卖出
hold[i] = max(hold[i - 1], cash[i - 1] - prices[i]); // 这里取最大值是希望花出去的成本小,即在低价时买入


  1. 如何定义最优解的值?最优解即为最终的状态值。在动态规划问题中,一般定义 dp[i] 为前面一些列状态的最优解。

  2. 如何计算最优解的值?一般采用自底向上的方式计算,即先计算最简单的子问题,如本题中第二天的股票是否买卖。(这个点细究起来有很多可玩的东西,今天没时间写了,有时间再更新!)
    cash[1] = max(cash[0], hold[0] + prices[1]) = max(0, -7+1)
    hold[1] = max(hold[0], cash[0] - price[1]) = max(-7, 0-1)


有同学问为什么这样就能得到全局最优解?
这就是贪心与动态规划的联系,本节不做详细讲解。
“贪心算法” 在每一步总是做出在当前看来最好的选择(局部最优解),我们只是寄希望这样的选择能导致全局最优解。

  • “贪心算法” 和 “动态规划”、“回溯搜索” 算法一样,完成一件事情,是分步决策的;
  • “贪心算法” 在每一步总是做出在当前看来最好的选择, “最好” 的意思往往根据题目而来,可能是 “最小”,也可能是 “最大”;
  • 贪心算法和动态规划相比,它既不看前面(也就是说它不需要从前面的状态转移过来),也不看后面(无后效性,后面的选择不会对前面的选择有影响),因此贪心算法时间复杂度一般是线性的,空间复杂度是常数级别的。

这道题 “贪心” 的地方在于,对于 “今天的股价 - 昨天的股价”,得到的结果有 3 种可能:(1)正数(2)0(3)负数。贪心算法的决策是:只加正数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
动态规划是一种在数学优化中用于求解最优化问题的方法,常用于解决具有重叠子问题和最优子结构的问题,比如维空间中的物品装箱问题。在MATLAB中,可以使用这种算法来高效地解决维空间内如何尽可能多地放置满足大小限制的矩形物体,以达到最小化浪费空间的目的。 具体步骤包括: 1. 定义状态:在这个问题中,状态通常是每个位置(i, j)上能够放下多少个物体,或者能否放下一个特定尺寸的物体。 2. 建立状态转移方程:根据当前位置和物体的尺寸,确定是否能放入,并更新当前位置的状态值,要考虑已经放入的物体对后续放置的影响。 3. 初始化:创建一个维数组来表示状态,通常开始时所有位置都无法放置物体,状态为0。 4. 动态规划遍历:从左上角开始,使用递推的方式填充这个数组,直到遍历完整个维空间。 5. 最终状态:在状态数组右下角的元素将给出在给定尺寸约束下能放置的最大物体数量。 6. 反向追踪:找到放置路径,即回溯状态数组,记录每个位置的最优解。 以下是一个简单的MATLAB代码示例,用于解决维装箱问题: ```matlab function [maxObjects, positions] = twoDimensionalBinPacking(rectangles, maxRectSize) % rectangles: 一个矩形数组,每个元素包含矩形的宽度和高度 % maxRectSize: 可以放入的最大矩形尺寸 % 初始化状态矩阵,所有位置都是未被占用 numRows = size(rectangles, 1); numCols = size(rectangles, 2); dp = zeros(numRows, numCols); % 填充状态矩阵 for i = 1:numRows for j = 1:numCols for rect = rectangles if isInside(rect, [i, j], maxRectSize) && dp(i-rect(1), j-rect(2)) == 0 dp(i, j) = dp(i-rect(1), j-rect(2)) + 1; positions{i, j} = rect; % 保存位置信息 end end end end % 找到最大物品数 maxObjects = max(dp(:)); % 返回最大物品数和位置信息 [~, idx] = max(dp(:)); positions = positions(idx); end % 判断一个矩形是否能完全放入指定位置 function isInside(rect, pos, maxRectSize) return pos(1) >= rect(1) && pos(2) >= rect(2) && pos(1) + rect(1) <= maxRectSize(1) && pos(2) + rect(2) <= maxRectSize(2); end ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值