LeetCode刷题:动态规划

例题

5.最长回文子串

https://leetcode-cn.com/problems/longest-palindromic-substring/
在这里插入图片描述多条件的动态规划,多条件填表
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

class Solution {
    
    
    public int minDistance(String word1, String word2) {
    
    
        int n = word1.length();
        int m = word2.length();
 
        // 有一个字符串为空串
        if (n * m == 0) {
    
    
            return n + m;
        }
 
        // DP 数组
        int[][] D = new int[n + 1][m + 1];
 
        // 边界状态初始化,需要这么多操作才能完成转换过程
        for (int i = 0; i < n + 1; i++) {
    
    
            D[i][0] = i;
        }
        for (int j = 0; j < m + 1; j++) {
    
    
            D[0][j] = j;
        }
 
        // 计算所有 DP 值
        for (int i = 1; i < n + 1; i++) {
    
    
            for (int j = 1; j < m + 1; j++) {
    
    
                int left = D[i - 1][j] + 1;
                int down = D[i][j - 1] + 1;
                int left_down = D[i - 1][j - 1];
                if (word1.charAt(i - 1) != word2.charAt(j - 1)) {
    
    
                    left_down += 1;
                }
                D[i][j] = Math.min(left, Math.min(down, left_down));
            }
        }
        return D[n][m];
    }
}

不同的二叉搜索树

https://leetcode-cn.com/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode-solution/
在这里插入图片描述在这里插入图片描述实际上就是推导公式,得到动态规划的状态转移方程

class Solution {
    
    
    public int numTrees(int n) {
    
    
        int[] G = new int[n + 1];
        G[0] = 1;
        G[1] = 1;
 
        for (int i = 2; i <= n; ++i) {
    
    
            for (int j = 1; j <= i; ++j) {
    
    
                G[i] += G[j - 1] * G[i - j];
            }
        }
        return G[n];
    }
}

139.单词拆分

https://leetcode-cn.com/problems/word-break/
在这里插入图片描述
一维遍历形式的动态规划:
在这里插入图片描述
在这里插入图片描述

public class Solution {
    
    
    public boolean wordBreak(String s, List<String> wordDict) {
    
    
        Set<String> wordDictSet = new HashSet(wordDict);
        boolean[] dp = new boolean[s.length() + 1];
        dp[0] = true;
        for (int i = 1; i <= s.length(); i++) {
    
    
            for (int j = 0; j < i; j++) {
    
    
                if (dp[j] && wordDictSet.contains(s.substring(j, i))) {
    
    
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }
}

53.最大子序和

在这里插入图片描述

一维形式的动态规划

class Solution {
    
    
    public int maxSubArray(int[] nums) {
    
    
        int pre = 0, maxAns = nums[0];
        for (int x : nums) {
    
    
            pre = Math.max(pre + x, x);
            maxAns = Math.max(maxAns, pre);
        }
        return maxAns;
    }
}

https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode-solution/

64.最小路径和

在这里插入图片描述https://leetcode-cn.com/problems/minimum-path-sum/

动态规划解法:

初始化:
第一列与第一行是固定的,只能来自上一格或者左一格的元素过来

dp方程:
之后的dp[i][j],可以来自于两个方向,左或者上(路径的方向只能是向下或向右)
综上,状态转移方程:
在这里插入图片描述

dfs解法:
https://leetcode-cn.com/problems/minimum-path-sum/solution/dfs-ji-yi-ji-hu-100-by-piaohao/
自底向上解法,需要加记忆

class Solution {
    
    
    private int M;
    private int N;
    private int[][] memo;
    //dfs + 记忆
    public int minPathSum(int[][] grid) {
    
    
        M = grid.length;
        N = grid[0].length;
        memo = new int[M][N];
        for (int i = 0; i < M; i++) {
    
    
            Arrays.fill(memo[i], -1);
        }
        return dfs(grid, 0, 0);
    }
 
    private int dfs(int[][] grid, int r, int c) {
    
    
        //fail,若越界,则认为不可达,距离为无穷大
        if (r < 0 || r >= M || c < 0 || c >= N) return Integer.MAX_VALUE;
        if (memo[r][c] > -1) return memo[r][c]; // 只要有就返回
        //若到达终点,终点的贡献值是其本身
        if (r == M - 1 && c== N - 1) return grid[M - 1][N - 1];
 
        //右边的点到终点最短的路径,决策1:从右边走
        int right = dfs(grid, r, c + 1);
        //下面的点到终点的最短路径,决策2:从下边走
        int down = dfs(grid, r + 1, c);
        //取两者的较小值,计算出当前点的最小路径值
        int ans = Math.min(right, down) + grid[r][c];
                 // 记忆化存储
        memo[r][c] = ans;
        return ans;
    }
}

562. 矩阵中最长的连续1线段

在这里插入图片描述解法1:DFS。
遇到为1的,就让它做端点,开始在四个方向上遍历,返回这个点作为端点的最大结果即可。
https://leetcode-cn.com/problems/longest-line-of-consecutive-one-in-matrix/solution/ju-zhen-zhong-zui-chang-de-lian-xu-1xian-duan-by-l/
在这里插入图片描述

class Solution {
    
    
    public int longestLine(int[][] M) {
    
    
        if (M == null || M.length == 0 || M[0].length == 0)
            return 0;
        int ans = 0;
        int[][] horizontal = new int[M.length][M[0].length];
        int[][] vertical = new int[M.length][M[0].length];
        int[][] diagonal = new int[M.length][M[0].length];
        int[][] antidiagonal = new int[M.length][M[0].length];
        for (int i = 0; i != M.length; ++i) {
    
    
            for (int j = 0; j != M[0].length; ++j) {
    
    
                if (M[i][j] == 0) {
    
    
                    horizontal[i][j] = 0;
                    vertical[i][j] = 0;
                    diagonal[i][j] = 0;
                    antidiagonal[i][j] = 0;
                } else {
    
    
                    horizontal[i][j] = j > 0 ? horizontal[i][j - 1] + 1 : 1;
                    vertical[i][j] = i > 0 ? vertical[i - 1][j] + 1 : 1;
                    diagonal[i][j] = i > 0 && j > 0 ? diagonal[i - 1][j - 1] + 1 : 1;
                    antidiagonal[i][j] = i > 0 && j < M[0].length - 1 ? antidiagonal[i - 1][j + 1] + 1 : 1;
                    ans = Math.max(ans, horizontal[i][j]);
                    ans = Math.max(ans, vertical[i][j]);
                    ans = Math.max(ans, diagonal[i][j]);
                    ans = Math.max(ans, antidiagonal[i][j]);
                }
            }
        }
        return ans;
    }
}

91. 解码方法

在这里插入图片描述

class Solution {
    
    
    //状态定义:dp[i]为第i个位置解码方法的总数
    public int numDecodings(String s) {
    
    
        char[] chars = s.toCharArray();
        if (chars[0] == '0') return 0;
        int[] dp = new int[chars.length];
        dp[0] = 1;
        for (int i = 1; i < chars.length; i++) {
    
    
            if (chars[i] == '0') {
    
    
                //如果前一位不是1或者2,显然无法解码
                if (chars[i - 1] != '1' && chars[i - 1] != '2') return 0;
                //如果前一位是1或者2
                dp[i] = i == 1 ? 1 : dp[i - 2];
            } else if (chars[i - 1] == '1' || (chars[i - 1] == '2' && chars[i] >= '1' && chars[i] <= '6')) {
    
    
                dp[i] = i == 1 ? dp[i - 1] + 1 : dp[i - 1] + dp[i - 2];
            } else {
    
    
                dp[i] = dp[i - 1];
            }
        }
        return dp[chars.length - 1];
    }
}

https://leetcode-cn.com/problems/decode-ways/solution/san-chong-jie-fa-dfsyi-wei-dong-tai-gui-tfvin/

猜你喜欢

转载自blog.csdn.net/weixin_38370441/article/details/115250246