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];
    }
}

总结:

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

相关推荐
dtq04241 小时前
数据结构 - 树的概念
c语言·数据结构·学习·算法
Dream it possible!1 小时前
LeetCode_热题100_知识点总结
算法·leetcode·职场和发展
鶴哥只手遮天1 小时前
从像素到战场:红外场景仿真引擎的核心技术深度解析
算法
anew___1 小时前
《从零手写操作系统 (19):Ext2文件系统实战——从内存到磁盘的跨越》
java·服务器·前端·数据库·算法
盘古开天16661 小时前
PPO算法原理详解(上):从策略梯度到近端策略优化的演进之路
人工智能·算法·机器学习·强化学习·ppo
云栈开源日记1 小时前
机器人运动规划从A*到Minimum Snap四大算法全解析
算法·ai·机器人
H.莓飛1 小时前
【数据结构】栈
linux·开发语言·数据结构·算法·centos
我就是不信2 小时前
C语言排序问题详解:从冒泡到快排的完整指南
c语言·算法·排序算法
l1t2 小时前
DeepSeek总结的PIVCO-Huffman编码性能优化
数据结构·c++·算法