二维动态规划

64. 最小路径和

 public int minPathSum(int[][] grid) {
        /**
        严格位置依赖的DP+空间压缩技巧
        整个大过程就是从上到小不停更新一维数组
        其中更新一维数组的小过程就是从左到右
         */
        int n = grid[0].length;
        int m = grid.length;
        // 用一个一维数组动态更新来记录想象中的二维缓存表
        int[] dp = new int[n];
        // 记录想象表的第0行,就是由grip表第0行从左往右计算得到
        dp[0]=grid[0][0];
        for(int j= 1; j<n; j++){
            dp[j]=dp[j-1]+grid[0][j];
        }
        // 从上到小的大过程
        for(int i = 1; i<m;i++){
            // 0位置的更新
            dp[0]+=grid[i][0];
            // 从左到右的小过程
            for(int j=1; j<n;j++){
                // 当前位置的值取决于左边和上边的最小值
                dp[j]=grid[i][j]+Math.min(dp[j-1],dp[j]);
            }
        }
        return dp[n-1];
    }
  • 时间复杂度:O(m*n)

1143. 最长公共子序列

 public int minPathSum(int[][] grid) {
        /**
        严格位置依赖的DP+空间压缩技巧
        整个大过程就是从上到小不停更新一维数组
        其中更新一维数组的小过程就是从左到右
         */
        int n = grid[0].length;
        int m = grid.length;
        // 用一个一维数组动态更新来记录想象中的二维缓存表
        int[] dp = new int[n];
        // 记录想象表的第0行,就是由grip表第0行从左往右计算得到
        dp[0]=grid[0][0];
        for(int j= 1; j<n; j++){
            dp[j]=dp[j-1]+grid[0][j];
        }
        // 从上到小的大过程
        for(int i = 1; i<m;i++){
            // 0位置的更新
            dp[0]+=grid[i][0];
            // 从左到右的小过程
            for(int j=1; j<n;j++){
                // 当前位置的值取决于左边和上边的最小值
                dp[j]=grid[i][j]+Math.min(dp[j-1],dp[j]);
            }
        }
        return dp[n-1];
    }
  • 时间复杂度:O(m*n)

516. 最长回文子序列

思路一:原始串与逆序串的最长公共子序列,就是原串的最长回文子序列

思路二:区间dp,从区间的首尾来尝试,整个过程是从下往上,从左往右,要得到的是右上角。分三种情况:1.对角线:区间长度为1;2.副对角线,区间长度为2;3.其余位置,又分为区间端点值相等否两种情况讨论。

1)当区间值不等(s[L] != s[R])时,取[L,R-1] 和 [L+1, R] 区间的最大值

2)当区间值相等(s[L] == s[R])时,2+[L+1, R+1]

public int longestPalindromeSubseq(String s) {
        char[] str = s.toCharArray();
        int n =str.length;
        int[] dp=new int[n];
    // 区间dp
        for(int l=n-1, leftDown=0,backUp;l>=0;l--){
            dp[l]=1;
            if(l+1<n){
                leftDown = dp[l+1];
                dp[l+1]= str[l]==str[l+1] ? 2 : 1;
            }
            for(int r=l+2; r<n; r++){
                backUp=dp[r];
                if(str[l]==str[r]){
                    dp[r]=2+leftDown;
                }else{
                    dp[r]=Math.max(dp[r],dp[r-1]);
                }
                leftDown=backUp;
            }
        }        
        return dp[n-1];
    }

329. 矩阵中最长的递增子序列

该题无法整理出严格位置依赖,其路径取决于上下左右中小的一个。不过题意严格递增,不会出现走回头路的情况,只需要挂个dp表记录即可。

 public int longestIncreasingPath(int[][] matrix) {
        int n = matrix.length;
        int m = matrix[0].length;
        int[][] dp=new int[n][m];
        int ans=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                ans=Math.max(ans,f(matrix,i,j,dp));
            }
        }
        return ans;
    }
    public int f(int[][] matrix, int i, int j, int[][] dp){
        // 只要更新过就不为0,因为至少包含本身,至少为1
        if(dp[i][j]!=0){
            return dp[i][j];
        }
        int next=0;
        if(i>0 && matrix[i][j]<matrix[i-1][j]){
            next=Math.max(next,f(matrix,i-1,j,dp));
        }
        if(i+1<matrix.length && matrix[i][j]<matrix[i+1][j]){
            next=Math.max(next,f(matrix,i+1,j,dp));
        }
        if(j>0 && matrix[i][j]<matrix[i][j-1]){
            next=Math.max(next,f(matrix,i,j-1,dp));
        }
        if(j+1<matrix[0].length && matrix[i][j]<matrix[i][j+1]){
            next=Math.max(next,f(matrix,i,j+1,dp));
        }
        // 注意加上自身,长度+1
        dp[i][j]=next+1;
        return next+1;
    }

97. 交错字符串 

public boolean isInterleave(String s1, String s2, String s3) {
        // 当s1和s2的长度和都不等于s3的长度时,一定不是交错字符串
        if(s1.length() + s2.length() != s3.length()){
            return false;
        }
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        char[] str3 = s3.toCharArray();
        int n = str1.length;
        int m = str2.length;
        // s1[前缀长度为i]和s2[前缀长度为j],能否交错组成s3[前缀长度为i+j]
        boolean[] dp = new boolean[m+1];
        dp[0] = true;
        // 严格位置依赖, 依赖于左和上方格子
        for(int j = 1; j<=m; j++){
            // 对应于想象的二维表第0行,左
            if(str2[j-1]!=str3[j-1]){
                break;
            }
            dp[j]=true;
        }
        for(int i = 1;i<=n; i++){
            // 对应于想象的二维表第0列,当有一个不满足时,后面的全是false
            dp[0] = str1[i-1]== str3[i-1] && dp[0];
            for(int j=1;j<=m;j++){
                // 左和上
                dp[j]=(str1[i-1]==str3[i+j-1] && dp[j])
                ||(str2[j-1]==str3[i+j-1] && dp[j-1]);
            }
        }
        return dp[m];
    }
  •  时间复杂度O(m*n)

72. 编辑距离

public int minDistance(String word1, String word2) {
        char[] s1 = word1.toCharArray();
        char[] s2 = word2.toCharArray();
        int n =s1.length;
        int m=s2.length;
        // s1[前i个]变成s2[前j个]的最少操作
        // 空间压缩,依赖于左上角、左边、上边的值
        int[] dp = new int[m+1];
        // 对应于想象表的第0行,插入*i
        for(int j = 1; j<= m ; j++){
            dp[j]=j;
        }
        for(int i = 1,leftUp,backUp; i<=n;i++){
            dp[0]=i;
            leftUp=(i-1);
            for(int j=1; j<=m;j++){
                backUp=dp[j];
                if(s1[i-1]==s2[j-1]){
                    dp[j]=leftUp;
                }else{
                    dp[j]=Math.min(Math.min(dp[j-1]+1,dp[j]+1),leftUp+1);
                }
                leftUp=backUp;
            }
        }
        return dp[m];

    }
  •  时间复杂度O(m*n)

115. 不同的子序列

 public int numDistinct(String s, String t) {
        // 已结尾字符讨论,要得到的是右下角
        // dp[i][j]:s[i个字符]的子序列有几个等于t[j个]
        char[] s1 = s.toCharArray();
        char[] s2 = t.toCharArray();
        int n = s1.length;
        int m = s2.length;
        int[] dp = new int[m+1];
        dp[0]=1;
        for(int i=1; i<=n;i++){
            // 取决于左上角和上边的值,所以,从右往左
            for(int j=m; j>=1; j--){
                // 两种情况,相等时,等于左上角
                // 不等时,等于上边的值,因此不用更新
                if(s1[i-1]==s2[j-1]){
                    dp[j]+=dp[j-1];
                }
            }
        }
        return dp[m];
    }
  •  时间复杂度O(m*n)
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值