第四篇:动态规划及习题
动态规划常用于求最优解。
把一个规模比较大的问题分成几个规模比较小的问题,然后由小的问题推导出大的问题。
动态规划就三步:
第一步:定义数组元素的含义,如dp[i]代表什么意思,dp[i][j]代表什么意思
第二步:找出数组元素之间的关系
第三步:找出初始值
leetcode题目:
力扣70、爬楼梯。easy。
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
这道题有一个关键点就是【爬到第n阶的办法数】=【爬到第n-1阶的办法】+【爬到第n-2阶的办法】。这个始终想不明白,暂时当成一个结论来看吧。
n=1时,只有1种方法,即【1个1】
n=2时,有2种方法,即【2个1】,或【1个2】
n=3时,有3种方法,即【3个1】,或【1个1,1个2】,或【1个2,1个1】
n=4时,有5种方法,即【4个1】,或【2个2】,或【1个1,1个2,1个1】,或【1个2,2个1】,或【2个1,1个2】
当n>=3时,需要建一个数组arr,数组长度为n+1。arr[n]表示爬到第n阶的办法数。对于任意一个索引大于等于3的元素,值都是前两个元素的和。
public int climbStairs(int n) { if (n == 1) { return 1; } else if (n == 2) { return 2; } int[] arr = new int[n + 1]; arr[1] = 1; arr[2] = 2; for (int i = 3; i < arr.length; i++) { arr[i] = arr[i - 1] + arr[i - 2]; } return arr[n]; }
第一步,定义数组元素的含义。arr[i]表示爬到第i阶的办法数
第二步,找出数组元素之间的关系。arr[i] = arr[i - 1] + arr[i - 2]
第三步,找出初始值。arr[1]=1,arr[2]=2
力扣5、最长回文子串。med。
对于一个字符串而言,如果它是回文串,并且长度大于2,那么将它首尾的两个字母去除之后,它仍然是个回文串。根据这样的思路,我们就可以用动态规划的方法解决本题。
首先定义数组元素的含义,定义一个数组dp[][],dp[i][j]值为1表示s[i:j]不是回文串,值为2表示s[i:j]是回文串。s[i:j]表示索引从i到j的字符串,包括i和j。
其次定义状态转移方程,dp[i][j] = (arr[i] == arr[j] && dp[i + 1][j - 1] == 2) ? 2 : 1,arr是原始字符串转换的字符数组。dp[i][j]的值依赖dp[i+1][j-1]的值,也就是说要先计算出dp[i+1][j-1]的值,才能计算出dp[i][j]的值。从二维数组对应的表格来看,先计算左下角的值,再计算右上角的值。该怎么遍历呢?这里每次自己写都搞不定
如果是在遍历i的内部遍历j,即
for(int i=0;i<arr.length;i++){
for(int j=i+1;j<arr.length;j++){
}
}
那么,
i=0时,给dp[0][1]赋值为2,给dp[0][2]赋值为2,给dp[0][3]赋值出现了问题,因为dp[1][2]不知道是多少。
其实还有另一种遍历方式,自己之前从来没有用过,那就是在遍历j的内部遍历i,即
for(int j=0;j<arr.length;j++){
for(int i=0;i<j;i++){
}
}
那么,
j=1时,给dp[0][1]赋值为2。
j=2时,给dp[0][2]赋值为2,给dp[1][2]赋值为2。
j=3时,给dp[0][3]赋值为dp[1][2],又dp[1][2]值为2,所以dp[0][3]值为2。给dp[1][3]赋值为2,给dp[2][3]赋值为2。
j=4时,给dp[0][4]赋值为dp[1][3],又dp[1][3]值为2,所以dp[0][4]值为2。给dp[1][4]赋值为dp[2][3],又dp[2][3]值为2,所以dp[1][4]值为2。给dp[2][4]赋值为2,给dp[3][4]赋值为2。
依次类推。。。
最后计算初始值
力扣409、最长回文串
题目和力扣5相似,所以一起研究下。
力扣62、不同路径。med。
首先定义数组元素的含义,创建一个二维数组,定义dp[i][j]的值是机器人从左上角移动到位于索引i行、索引j列的方块的路径数(i、j都从0开始,表示第一行、第一列)。因为机器人每次只能向下或者向右移动一步,故dp[i][j] = dp[i-1][j] + dp[i][j-1]。i等于0时,dp[i][j]等于1。i>=1时,如果j等于0,dp[i][j]等于1,如果j>=1,则dp[i][j] = dp[i-1][j] + dp[i][j-1]。
力扣63、不同路径II。med。
首先定义数组元素的含义,创建一个二维数组,定义dp[i][j]的值是机器人从左上角移动到位于索引i行、索引j列的方块的路径数(i、j都从0开始,表示第一行、第一列)。如果索引i行、索引j列的方块上有障碍,则dp[i][j]值为0,否则在i>0、j>0时,dp[i][j]=dp[i-1][j] + dp[i][j-1],即dp[i][j] = obstacleGrid[i][j] == 1 ? 0 : dp[i-1][j] + dp[i][j-1]。i=0是第一行的情况,第一行不用考虑从上面下来的情况,只需考虑从左边过来的情况,j=0是第一列的情况,第一列不用考虑从左边过来的情况,只需考虑从上面下来的情况,则dp[i][j] = obstacleGrid[i][j] == 1 ? 0 : (i - 1 < 0 ? 0 : dp[i-1][j]) + (j - 1 < 0 ? 0 : dp[i][j-1]。但是这样算下来,dp所有元素值都为0。这是因为dp[0][0]等于0了,而dp[0][0]在obstacleGrid[i][j]值等于1时为0,在obstacleGrid[i][j]值等于0时为1。赋此初始值之后,就可以正确算出dp各元素值了。
力扣980、不同路径III。hard。
首先定义数组元素的含义,
力扣44、通配符匹配
思路:
浙公网安备 33010602011771号