第四篇:动态规划及习题

动态规划常用于求最优解。

把一个规模比较大的问题分成几个规模比较小的问题,然后由小的问题推导出大的问题。

动态规划就三步:

第一步:定义数组元素的含义,如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、通配符匹配

思路:

posted on 2019-10-28 22:29  koushr  阅读(6474)  评论(0)    收藏  举报

导航