

详解三道一维的动态规划算法题
source link: http://mp.weixin.qq.com/s?__biz=MzIzMTE1ODkyNQ%3D%3D&%3Bmid=2649412348&%3Bidx=1&%3Bsn=55fa1f0c701f763d1bad45b5c2ddfded
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

来源: 知乎
作者: 单金折
前阵子写了两篇动态规划的文章
后面说要给大家讲解一些案例,不过一直没讲,由于前阵子手受伤了导致手不能运动,一直没给大家写文章,所以呢,我就找一些感觉还不错的文章供大家消费。
例1: 打家劫舍
动态规划思考步骤:
1、原问题:
在一条直线上,有n个房屋,每个房屋中有数量不等的财宝,有一个盗 贼希望从房屋中盗取财宝,由于房屋中有报警器,如果同时从相邻的两个房屋中盗取财宝就会触发报警器。问在不触发报警器的前提下,最多可获取多少财宝?例如 [5,2,6,3,1,7],则选择5,6,7
来源于LeetCode 198. House Robber
2 、子问题:
(1)、只考虑前两个房间时,谁大选谁
(2)、考虑第三个房间
-
如果偷第三个房间,则意味着第二个房间不投,也就是第三个房间值 + 第一个房间的宝藏数量
-
如果不偷第三个房间,则宝藏数量等于前两个房间宝藏数量
3、确认状态:
int [] nums; // 各个房间的宝藏数
int [] flags = new int [n]; // 记录各个房间有没有被偷,若flag = 0 则没偷, flag = 1 则偷了。
int [] dp = new int [n]; // dp[i]表示前i个房间偷到的最大宝藏数
4、初始状态:
第一个房间:
-
Condistion 1 :dp[0] = nums[0] ; flags[0] = 1;
-
Condistion 2 :dp[0] = 0; flags[0] = 0;
第二个房间:
-
Condistion 1 :when flags[1] = 1; dp[1] = nums[1];
-
Condistion 2 :whenflags[1] = 0; dp[1] = dp[0];
-
选 Condistion 1 还是 Condistion 2呢?比较 两种情况下dp[1]的大小
推广到前i个房间: (i>=2)
-
when flags[i] = 1, dp[i] = nums[i] + dp[i-2]
-
when flags[i] = 0; dp[i] = dp[i-1]
5、状态转移方程:
dp[0] = nums[0]; dp[1] = max(nums[0],nums[1]); for(int i = 2;i<n;i++) dp[i] = max(nums[i] + dp[i-2],dp[i-1])
6、代码实现
class Solution { public int rob(int[] nums) { if(nums.length == 0) return 0; int [] dp = new int[nums.length]; dp[0] = nums[0]; // 每次做数组判定时都需要做数组边界判定,防止越界 if(nums.length < 2) return nums[0]; dp[1] = (nums[0]>nums[1]) ? nums[0] : nums[1]; for(int i = 2;i<nums.length;i++) dp[i] = ((nums[i] + dp[i-2]) > dp[i-1]) ? (nums[i]+dp[i-2]) : dp[i-1]; return dp[nums.length-1]; } }
例2:最大子段和
动态规划思考步骤:
1、原问题
给定一个数组,求这个数组的连续子数组中,最大的那一段的和。
如数组[-2,1,-3,4,-1,2,1,-5,4] 的子段为:[-2,1]、[1,-3,4,-1]、[4,-1,2,1]、…、[-2,1,-3,4,-1,2,1,-5,4],和最大的是[4,1,2,1],为6。
示例: Input: int [] nums = [-2,1,-3,4,-1,2,1,-5,4], Output: 6 Explanation: [4,-1,2,1] has the largest sum = 6.
来源于LeetCode 53. Maximum Subarray
2、子问题
-
只考虑第一个元素,则最大子段和为其本身 DP[0] = nums[0]
-
考虑前两个元素,最大子段和为 nums[0],num[1]以及 nums[0] + num[1] 中最大值 设为DP[1]
-
考虑前三个元素,如何求其最大子段和?还是分为两种情况讨论,第三个元素在最后的字串内吗?
-
若第三个元素也包含在最后的字串内,则DP[2] = Max(DP[1]+nums[2] , nums[2])
-
3、确认状态
DP[i] 为 以nums[i]结尾的子段的最大最短和
例如 DP[1]则为以nums[1]结尾的最大字段和
4、初始状态
dp[0] = nums[0]
dp[1] = max(dp[0]+nums[1] , nums[1])
5、状态转移方程:
dp[i] = max(dp[i-1]+nums[i],nums[i])
6、解题代码:
public class lc53_MaximumSubarray { public int maxSubArray(int[] nums) { int len = nums.length; if(len == 0) return 0; int [] dp = new int[len]; dp[0] = nums[0]; int max = dp[0]; for (int i = 1; i<len;i++){ dp[i] = (dp[i-1]+nums[i] > nums[i]) ? dp[i-1]+nums[i] : nums[i]; if (dp[i]>max) max = dp[i]; } return max; } }
例3:找零钱
已知不同面值的钞票,求如 何用最少数量的钞票组成某个金额,求可 以使用的最少钞票数量。如果任意数量的已知面值钞票都无法组成该金额, 则返回-1。
示例: Input: coins = [1, 2, 5], amount = 11 Output: 3 Explanation: 11 = 5 + 5 + 1 Input: coins = [2], amount = 3 Output: -1
来源于LeetCode 322. Coin Change
动态规划解题步骤:
将原问题拆分成子问题
-
已知什么?显而易见,钞票的金额都只需要其本身1张即可
-
如何在已知钞票的情况下构造出 金额X需要的最少钞票组合
确认状态
DP[0] - DP[amount] 表示构造金额amount需要的最小钞票数
确认边界状态(初始条件)
-
DP[coin] = 1 其他的都未知初始值设为 -1
-
例如coins = [1, 2, 5], amount = 11 已知 dp[1]、dp[2]、dp[5] =1
-
现在已知 DP[coin] 需要求出每一个DP[amount]
状态转移方程
dp[i] = min(dp[i-1], dp[i-2], dp[i-5]) + 1
解题代码:(java)
public int coinChange(int[] coins, int amount) { int len = coins.length; if (len == 0 || amount<0) return -1; if (amount==0) return 0; int [] dp = new int[amount+1]; for (int i = 0; i <= amount; i++){ dp[i] = -1; } for (int i = 0; i< len;i++){ if(coins[i] == amount) return 1; if(coins[i] < amount) dp[coins[i]] = 1; } // State Transfer Function for(int i = 1; i <= amount;i++){ for (int j = 0; j < len; j++){ if (i - coins[j] >= 0 && dp[i - coins[j]] != -1){ if (dp[i] == -1 || dp[i] > dp[i - coins[j]] + 1){ dp[i] = dp[i - coins[j]] + 1; } } } } return dp[amount]; }
总结
今天实例了三道一维的题,属于 leetcode 中 medium 级别的题吧,大家也可以根据题号去搜索练练手。
Recommend
-
8
一维条形码攻击技术(Badbarcode) 数据流
-
29
预计阅读时间:15 分钟 KMP 算法(Knuth-Morris-Pratt 算法)是一个著名的字符串匹配算法,效率很高,但是确实有点复杂。 很多读者抱怨 KMP 算法无法理解,这很正常,想到大学教材...
-
18
如何使用单调栈解题 👆让天下没有难刷的算法!若 GitBook 访问太慢,可尝试
-
10
前言 嗨,大家好,我是asong,鸽了好久,其实元旦就想写一下这篇文章,但是因为喝酒喝断片了,养了三天才缓过来,就推迟到这个周末了,不过多追溯了,有点丢人。今天与大家来聊一聊 go 中的关键字 defer
-
8
numpy 的一维向量如何参与计算 作者: 张志强 ,...
-
4
动态规划之 KMP 算法详解(配代码版)-五分钟学算法 当前位置:五分钟学算法 > 算法 > 传统算法
-
7
V2EX › 程序员 百思不得其解: PHP 怎么把一维数组的键值转化为多维数组的键名
-
6
#yyds干货盘点# leetcode算法题:一维数组的动态和 原创 灰太狼_cxh 2022...
-
5
基于GMM的一维时序数据平滑算法 作者:佚名 2023-06-01 15:48:40 本文将介绍我们使用高斯混合模型(GMM)算法作为一维数据的平滑和去噪算法。 本文将介绍我...
-
5
①动态规划 动态规划(Dynamic Programming,DP)是运筹学的一个分支,是求解决策过程...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK