算法-动态规划(爬楼梯、不同路径、编辑距离)

动态规划算法思想:

动态规划思想

动态规划算法要素:

算法-动态规划(爬楼梯、不同路径、编辑距离)_第1张图片

总结:
(1)当前问题的最优解可以由前一步的最优解得到
(2)运用一维数组或者二维数组推导递推关系
(3)初始化

LeetCode例题

#70爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

当前台阶数为n,可以由(n-1)或者(n-2)级台阶上来。假设用d[i]数组来记录爬上i级台阶的方法个数,那么递推关系为:
d[n]=d[n-1]+d[n-2]
初始化:
d[1]=1 爬上一级台阶有一种方法(1)
d[2]=2 爬上两级台阶有两种方法(1,1),(2)

Java代码:

    public int climbStairs(int n) {
        if (n == 1) {
            return 1;
        }
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }

#62不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

问总共有多少条不同的路径?
算法-动态规划(爬楼梯、不同路径、编辑距离)_第2张图片
(1)判断当前解可否通过前一个解得到?
Finish位置,只可以从前一个位置上边A或者左边B走到,假设走到A有n种方法,走到B有m种方法,那么走到Finish位置则有m+n种方法,得到递推关系为:
d[i][j]=d[i-1][j]+d[i][j-1] 其中i为行数,j为列数
初始化:
因为第一行只可以通过一直往右走得到,所以只有一条路径;所以将第一行初始化为1,同理第一列初始化为1.
Java代码:

    public int uniquePaths(int m, int n) {
        int d[][]=new int[m][n];
        if(m==1||n==1)
            return 1;
        if(m==0||n==0)
            return 0;
        for(int i=0;i<m;i++)
            d[i][0]=1;
        for(int j=0;j<n;j++)
            d[0][j]=1;
        for(int i=1;i<m;i++)
            for(int j=1;j<n;j++)
                d[i][j]=d[i-1][j]+d[i][j-1];
        return d[m-1][n-1];
    }

#72编辑距离
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符

《趣学算法》 这本书将该题作为例题来介绍动态规划的解法
递推关系:
d[i][j]=min{d[i-1][j]+1,d[i][j-1]+1,d[i-1][j-1]+diff}
其中,如果word1.charAt(i)==word2.charAt(j),diff=0;否则diff=1;d[i][j]表示最小操作数。
如果,d[i][j]=d[i-1][j]+1,可以理解为插入word1插入一个字符变成了word2;
如果,d[i][j]=d[i][j-1]+1,可以理解为插入word1删除一个字符变成了word2;
如果,d[i][j]=d[i-1][j-1]+diff,可以理解为插入word1进行了替换(或者没有)变成了word2;
初始化:
for(int i=0;i d[i][0]=i;
for(int j=0;j d[0][j]=j;
具体含义建议做表格自行体会

Java代码:

    public int minDistance(String word1, String word2) {
        int len1=word1.length();
        int len2=word2.length();
        if(len1*len2==0)
            return len1+len2;
        //采用len+1的原因是为了和空串进行比较,方便进行初始化
        int check[][]=new int[len1+1][len2+1];
        //初始化,由空串变为word时所需要的操作数
        for(int i=0;i<len1+1;i++)
            check[i][0]=i;
        for(int j=0;j<len2+1;j++)
            check[0][j]=j;
        int min=0;
        int temp=0;
        //比较
        for(int i=1;i<len1+1;i++)
            for(int j=1;j<len2+1;j++)
            {
                if(word1.charAt(i-1)==word2.charAt(j-1))
                    temp=check[i-1][j-1];
                else temp=check[i-1][j-1]+1;
                min=Math.min(check[i][j-1]+1,check[i-1][j]+1);
                min=Math.min(min,temp);
                check[i][j]=min;
            }
        return check[len1][len2];

    }

总结

动态规划无论运用一维数组还是二维数组,其中都每个位置都有着具体的涵义,只有了解其中的含义以及当前求解问题与前一求解问题的联系,才能真正体会到动态规划算法的妙处。

你可能感兴趣的:(算法,动态规划,算法,动态规划,java,leetcode)