hot100多维动态规划刷题

62. 不同路径 - 力扣(LeetCode)

公式为:dpij = dpi-1j+dpij-1

初始化第一行第一列的值为1,任意IJ位置可以由上面和左边加起来得到路径数量

64. 最小路径和 - 力扣(LeetCode)

公式为:gridij = Math.min(gridi-1j,gridij-1)+gridij;

原地修改数组。

复制代码
class Solution {
    public int minPathSum(int[][] grid) {
        
        for(int i = 0; i < grid.length; i++){
            for(int j = 0; j < grid[0].length; j++){
                if(i == 0 && j ==0){
                    continue;
                }
                if(i == 0){
                   grid[0][j] =grid[0][j-1]+grid[0][j]; 
                   
                }else if(j == 0){
                   grid[i][0] =grid[i-1][0]+grid[i][0];
                   
                } else
                grid[i][j] = Math.min(grid[i-1][j],grid[i][j-1])+grid[i][j];
            }
        }
        return grid[grid.length-1][grid[0].length-1];
    }
}

5. 最长回文子串 - 力扣(LeetCode)

第一次写错了,错误原因为遍历顺序和初始化错误

复制代码
class Solution {
    public String longestPalindrome(String s) {
        // dp[i][j] = dp[i+1][j-1] + i,j是否相等
        // i, 0-n j i+1->n
        int maxl = 0;
        int maxr = 0;
        int maxlen = 1;
        boolean dp[][] = new boolean[s.length()][s.length()];
        for(int i = 0)
        for(int i = 0; i < s.length();i++){
            for(int j = i + 1; j < s.length();j++){
                if(s.charAt(i) == s.charAt(j) && (j-i==1||dp[i+1][j-1])){
                    dp[i][j]=true;
                    if(j-i+1 > maxlen){
                        maxlen = j-i+1;
                        maxl = i;
                        maxr = j;
                    }
                }
            }
        }
        return s.substring(maxl, maxr+1);
    }
}

公式为:dpij = (s.charAt(i) == s.charAt(j)) && (j - i <= 1 || dpi + 1j - 1);

i,j位置依赖的是左下的状态的值,需要让左下的值优先计算

修正后的代码如下:遍历顺序修改,需要从行最大列最小的开始计算,同时保证J>=I

复制代码
class Solution {
    public String longestPalindrome(String s) {
        // dp[i][j] = dp[i+1][j-1] + i,j是否相等
        // i, 0-n j i+1->n
        int maxl = 0;
        int maxr = 0;
        int maxlen = 1;
        boolean dp[][] = new boolean[s.length()][s.length()];
        // 保证j>=i
        for(int i = s.length()-1; i >= 0;i--){
            for(int j = i; j < s.length();j++){
                if(s.charAt(i) == s.charAt(j) && (j-i<=1||dp[i+1][j-1])){
                    dp[i][j]=true;
                    if(j-i+1 > maxlen){
                        maxlen = j-i+1;
                        maxl = i;
                        maxr = j;
                    }
                }
            }
        }
        return s.substring(maxl, maxr+1);
    }
}

1143. 最长公共子序列 - 力扣(LeetCode)

第一次写错:考虑从0,i和从0,j的索引位置的字符串组成的最大长度,初始化写的不对

不如改定义:推理含义: 两个字符串分别从前i和j个字符组成子序列的最大长度

//dpij = dpi-1j-1 +1 if (i==j)

// else = max(dpi-1j, dpij-1)

// 推理顺序:依赖左上的数据,都是从小到大遍历

// 初始化:不需要初始化

注意点为:获取字符的索引位置修改为i-1,j-1,保证dp的索引也不越界,到0行0列都为0.

复制代码
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        //推理含义: 两个字符串分别从前i和j个字符组成子序列的最大长度
        //dp[i][j] = dp[i-1][j-1] +1 if (i==j)
        // else = max(dp[i-1][j], dp[i][j-1])
        // 依赖左上的数据,都是从小到大遍历
        // 初始化:不需要初始化
        int dp[][] = new int[text1.length()+1][text2.length()+1];
        for(int i = 1; i <= text1.length();i++){
            for(int j = 1; j <= text2.length();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-1][j], dp[i][j-1]);
                }
            }
        }
        return dp[text1.length()][text2.length()];
    }
}

72. 编辑距离 - 力扣(LeetCode)

基于最长公共子序列思想

dpij代表把 word1 的前 i 个字符变成 word2 的前 j 个字符,所需的最少操作数。

基于哨兵做边界初始化防止-1越界

定义状态转移方程

复制代码
if(word1.charAt(i-1) == word2.charAt(j-1)){
    dp[i][j] = dp[i-1][j-1];
}else{
    int temp = Math.min(dp[i-1][j], dp[i-1][j-1]);
    dp[i][j] = Math.min(temp, dp[i][j-1])+1;
}

遍历顺序,依赖左上、上、左 → i、j 都从小到大

复制代码
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];
        // word2为空的时候,操作第一个字符串需要删除的次数
        for(int i = 0; i <=m;i++){
            dp[i][0]=i;
        }
        // word1为空的时候,操作第一个字符串需要插入的次数
        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++){
                // 如果ij相等,不用操作,考虑前面的就可以
                if(word1.charAt(i-1) == word2.charAt(j-1)){
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    // 否则,考虑i替换为j,或者i后面继续插入j位置的字符,或者删除i位置字符
                    int temp = Math.min(dp[i-1][j], dp[i-1][j-1]);
                    dp[i][j] = Math.min(temp, dp[i][j-1])+1;
                }
            }
        }
        return dp[m][n];
    }
}

总结:

考虑初始化,数组大小,状态方程,遍历顺序。

相关推荐
人工智能培训8 小时前
边缘AI与大模型轻量化:让智能跑进每一个终端
大数据·人工智能·算法·重构·生活
lengxuenong8 小时前
树状数组 · 信息学学习手册3-优化LIS
c++·学习·算法
动词ing9 小时前
【题目练习】外观数列
算法
余额瞒着我当琳9 小时前
C++11,发展历史浅谈,初始化列表和对象初始化,右值引用和移动语义
java·开发语言·c++·算法
suhan9 小时前
【数据结构】六、图:4.图的遍历(深度优先算法DFS、广度优先算法BFS)
数据结构·算法·排序算法
suhan9 小时前
【数据结构】六、图:3.十字链表、邻接多重表、边集数组
数据结构·算法·排序算法
Dola_Zou9 小时前
工商业储能系统核心策略
算法·自动化·软件工程
Tsuki_tl9 小时前
【优选算法:双指针】——复写零题解
java·c++·算法·leetcode·数组·双指针·复写零
Rain的Java大神之路9 小时前
面了上百人,我最爱问的LeetCode 1「两数之和」:能背代码的很多,能讲清“先查后存”的没几个
java·后端·算法