【LeetCode 手撕算法】(多维动态规划)不同路径、最小路径和、最长回文子串、最长公共子序列、编辑距离

二维的dp[ ] [ ]

62-不同路径

**思路:**记录每一位置的路线数,初始值最上最左设为1,dp[ i ] [ j ]=dp[ i-1 ][ j ]+dp[ i ][ j-1 ]

**注意:**注意边界从1开始遍历

java 复制代码
class Solution {
    public int uniquePaths(int m, int n) {
        int [][]dp =new int[m][n];
        for(int i=0;i<m;i++){
            dp[i][0]=1;
        }
        for(int i=0;i<n;i++){
            dp[0][i]=1;
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j]=dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}

64-最小路径和

**思路:**设置第一个位置初始值,由此设置上和右边界的初始值(累加)。开始遍历x位置 先判断上和左位置谁最小,然后加上当前位置,即所求值。返回最后一个。

注意: 边界已初始化,则遍历时从1开始

java 复制代码
class Solution {
    public int minPathSum(int[][] grid) {
        int m=grid.length;
        int n=grid[0].length;
        int [][] dp=new int[m][n];
        dp[0][0]=grid[0][0];
        for(int i=1;i<m;i++){
            dp[i][0]=dp[i-1][0]+grid[i][0];
        }
        for(int i=1;i<n;i++){
            dp[0][i]=dp[0][i-1]+grid[0][i];
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }
        return dp[m-1][n-1];
    }
}

5-最长回文子串

**思路:**用dp[ i ][ j ]来表示长度为i到j的是否回文,先判断特殊情况s为空,再判断长度为1,为2时;再执行长度为3,用start取匹配时的位置,用maxlen更新匹配时的最大长度。

核心判断:s.charAt( i )==s.charAt( j )&&dp[ i+1 ][ j-1]

**注意:**判断完边界再判断内部是否回文;

获取元素用charAt( ) , 截取用substring( i, j )

循环用长度len来走外循环

java 复制代码
class Solution {
    public String longestPalindrome(String s) {
        int n=s.length();
        if(n<2) {return s;}//s长度为0,1时
        boolean [][]dp =new boolean[n][n];//代表判断长度i,j之间的内容
        int maxlen=1; //用于结果返回,最大长度
        int start =0;//用于结果返回,开始值
        for(int i=0;i<n;i++){//初始化长度为1的
            dp[i][i]=true;
        }
        for(int i=0;i<n-1;i++){//初始化长度为2的
            if(s.charAt(i)==s.charAt(i+1)){
                dp[i][i+1]=true; //初始化i和i+1区间的值(长度为2)
                if(maxlen<2){  //更新取值
                    maxlen=2;
                    start=i;  //获取当前i(从0开始遍历的)
                }
            }
        }
        //从头开始,走s长度为3及以上的情况
        for(int len=3;len<=n;len++){
            for(int i=0;i+len<=n;i++){
                int j=i+len-1;  //右边界的值
                //判断边界是否回文,以及内部是否回文,小的值已初始
                if(s.charAt(i)==s.charAt(j)&&dp[i+1][j-1]){ 
                    dp[i][j]=true;
                    if(maxlen<len){
                        maxlen=len; //更新最长值
                        start=i;    //获取当前i(从0开始遍历的)
                    }
                }
            }
        }
        return s.substring(start,start+maxlen);//截取用substring()函数
    }
}

1143-最长公共子序列

思路:dp[ i ][ j ] 表示text1[ i ]text2[ j ] 的最长相同序列数,判断两串对应位置是否相同,并加一,否则选dp[ i-1][ j ] 或者**dp[ i ][ j -1]**的最大值

注意: 求数字则初始值为索引,从0开始,长度为n+1;

遍历时从1索引开始,可等于m、n , 判断方式看[ n-1 ]是否越界

java 复制代码
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int m=text1.length();
        int n=text2.length();
        int [][]dp=new int[m+1][n+1];//存两个位置i和j相同字符的最大数量
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(text1.charAt(i-1)==text2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
                    dp[i][j]=Math.max(dp[i][j-1],dp[i-1][j]);
                }
            }
        }
        return dp[m][n];
    }
}

72-编辑距离

思路:

情况 1:

dp[0][j] = j:空字符串变成 word2[0..j-1],需要插入 j 个字符

dp[i][0] = iword1[0..i-1] 变成空字符串,需要删除 i 个字符

情况 2:word1[i-1] == word2[j-1] 不用做任何操作,直接继承之前的结果:

dp[i][j] = dp[i-1][j-1]

情况 3:word1[i-1] != word2[j-1] 三种操作取最小值:

java 复制代码
dp[i][j] = min(
    dp[i-1][j] + 1,    // 删除 word1[i-1]
    dp[i][j-1] + 1,    // 插入 word2[j-1]
    dp[i-1][j-1] + 1   // 替换
)

**注意:**求数字则初始设置m+1长度,;

若相等则+1, 不等则考虑(删除、插入、替换)三者最小值,再+1;

注意条件边界取值

java 复制代码
class Solution {
    public int minDistance(String word1, String word2) {
        int m=word1.length();
        int n=word2.length();
        int [][]dp=new int[m+1][n+1];
        
        for(int i=0;i<=m;i++){//若一串为0时
            dp[i][0]=i;
        }
        for(int j=0;j<=n;j++){
            dp[0][j]=j;
        }
        //若相等
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(word1.charAt(i-1)==word2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];//与前一个相比,不需要改,数量相等直接继承
                }
                else{
                    //不等时,选三个的最小值 并+1
                    dp[i][j]=Math.min(Math.min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1])+1;
                }
            }
        }
        return dp[m][n];
    }
}
相关推荐
信码由缰8 小时前
Maven 4 核心亮点
java
被AI抢饭碗的人8 小时前
算法:数据结构
数据结构·算法
运筹vivo@8 小时前
leetcode每日一题: 跳跃游戏 IV
leetcode·游戏·宽度优先
_深海凉_8 小时前
LeetCode热题100-验证二叉搜索树
算法·leetcode·职场和发展
shehuiyuelaiyuehao8 小时前
算法27,二维前缀和
开发语言·python·算法
蒟蒻的贤8 小时前
编译原理里的冲突到底是什么?
考研·算法
春天的菠菜8 小时前
【私服】一步部署 Docker 私服
java·docker·容器
有味道的男人8 小时前
1688 跨境 API:多语言、跨境代采、独立站商品同步方案
java·服务器·前端
兩尛8 小时前
C++多线程,并发
java·开发语言