动态规划相关题目——NWU_LK

动态规划经典题目

  1. 爬楼梯(70题,509斐波那契数相同)
    在这里插入图片描述
class Solution {
    public int climbStairs(int n) {
        int[] dp=new int[n+1];
        if (n==1||n==2){
            return n;
        }
        dp[1]=1;dp[2]=2;
        for (int i=3;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
}
  1. 使用最小花费爬楼梯(746题)
    在这里插入图片描述
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int n =cost.length;
        int[] dp=new int[n+1];
        dp[0]=0;dp[1]=0;
        for (int i=2;i<=n;i++){
            dp[i]=Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
        }
        return dp[n];
    }
}
  1. 打家劫舍(198题)
    在这里插入图片描述
class Solution {
    public int rob(int[] nums) {
        if (nums.length==0){
            return 0;
        }
        if (nums.length==1){
            return nums[0];
        }
        int[] dp=new int[nums.length];
        dp[0]=nums[0];
        dp[1]=Math.max(nums[0],nums[1]);
        for (int i=2;i<nums.length;i++){
            dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
        }
        return dp[nums.length-1];
    }
}
  1. 打家劫舍2(213题)
    在这里插入图片描述
class Solution {
    public int rob(int[] nums) {
        if (nums.length==0) return 0;
        if (nums.length==1) return nums[0];
        if (nums.length==2) return Math.max(nums[0],nums[1]);
        return Math.max(rob(nums,0,nums.length-2),rob(nums,1,nums.length-1));
    }
    public int rob(int[] nums,int start,int end){
        int[] dp=new int[nums.length];
        dp[start]=nums[start];
        dp[start+1]=Math.max(nums[start],nums[start+1]);
        for (int i=start+2;i<=end;i++){
            dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
        }
        return dp[end];
    }
}
  1. 打家劫舍3(337题)
    在这里插入图片描述
class Solution {
    public int rob(TreeNode root) {
        int[] res= dfs(root);
        return Math.max(res[0],res[1]);
    }
    public int[] dfs(TreeNode node){
        if (node==null) return new int[]{0,0};
        int[] left = dfs(node.left);
        int[] right = dfs(node.right);
        int select = node.val + left[1] + right[1];
        int unselect = Math.max(left[0],left[1])+Math.max(right[0],right[1]);
        return new int[]{select,unselect};
    }
}
  1. 最大子序和(53题)
    在这里插入图片描述
class Solution {
    public int maxSubArray(int[] nums) {
        int[] dp=new int[nums.length];
        int max=nums[0];
        dp[0]=nums[0];
        for (int i=1;i<nums.length;i++){
            dp[i]=Math.max(dp[i-1]+nums[i],nums[i]);
            if (dp[i]>max){
                max=dp[i];
            }
        }
        return max;
    }
}
  1. 零钱兑换(322题)
    在这里插入图片描述
class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp=new int[amount+1];
        Arrays.fill(dp,-1);
        dp[0]=0;
        for (int i=1;i<=amount;i++){
            for(int coin:coins){
                if (i-coin>=0 && dp[i-coin]!=-1){
                    if (dp[i]==-1||dp[i-coin]+1<dp[i]){
                        dp[i]=dp[i-coin]+1;
                    }
                }
            }
        }
        return dp[amount];
    }
}
  1. 三角形最小路径和(120题)
    在这里插入图片描述
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n=triangle.size();
        int[][] dp=new int[n][n];
        dp[0][0]=triangle.get(0).get(0);
        for (int i=1;i<n;i++){
            dp[i][0]=dp[i-1][0]+triangle.get(i).get(0);
            for (int j=1;j<i;j++){
                int ele=triangle.get(i).get(j);
                dp[i][j]=ele+Math.min(dp[i-1][j-1],dp[i-1][j]);
            }
            dp[i][i]=dp[i-1][i-1]+triangle.get(i).get(i);
        }
        int min=dp[n-1][0];
        for (int j=1;j<n;j++){
            min=Math.min(min,dp[n-1][j]);
        }
        return min;
    }
}
  1. 最长上升子序列(300题)
    在这里插入图片描述
class Solution {
    public int lengthOfLIS(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int[] dp=new int[nums.length];
        dp[0]=1;
        int maxCount=1;
        for (int i=1;i<dp.length;i++){
            int m=0;
            for (int j=0;j<i;j++){
                if (nums[j]<nums[i]){
                    m=Math.max(dp[j],m);
                }
            }
            dp[i]=m+1;
            maxCount=Math.max(maxCount,dp[i]);
        }
        return maxCount;
    }
}
  1. 最小路径和(64题)
    在这里插入图片描述
class Solution {
    public int minPathSum(int[][] grid) {
        int[][] dp=new int[grid.length][grid[0].length];
        dp[0][0]=grid[0][0];
        for (int i=1;i<grid[0].length;i++){
            dp[0][i]=dp[0][i-1]+grid[0][i];
        }
        for (int j=1;j<grid.length;j++){
            dp[j][0]=dp[j-1][0]+grid[j][0];
        }
        for(int i=1;i<grid.length;i++){
            for(int j=1;j<grid[0].length;j++){
                dp[i][j]=Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }
        return dp[grid.length-1][grid[0].length-1];
    }
}
  1. K站中转内最便宜的航班(787题)
    在这里插入图片描述
class Solution {
    public int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) {
        // dp[i][k]是经过k个中转站后到达站 i 的最小费用
        int[][] dp = new int[n][K + 1];

        // 循环初始化整个二维数组。
        for(int i = 0; i < n; ++i) Arrays.fill(dp[i], Integer.MAX_VALUE);

        // 利用flights中的信息初始化src可直达的班次
        for(int[] flight : flights) {
            if(flight[0] == src){
                dp[flight[1]][0] = flight[2];
            }
        }

        // 循环初始化数组中dst == src的行
        for(int i = 0; i <= K; i++){
            dp[src][i] = 0;
        }

        //动态规划状态转移方程,开始填表
        //直达的已经初始化了(即k = 0的情况),现在从k = 1 的开始,即只有一个中转站开始
        for(int k = 1; k <= K; k++){
            for(int[] flight : flights){
                //结合题目理解
                if(dp[flight[0]][k - 1] != Integer.MAX_VALUE){
                    dp[flight[1]][k] = Math.min(dp[flight[1]][k], dp[flight[0]][k - 1] + flight[2]);
                }
            }
        }
        return dp[dst][K] == Integer.MAX_VALUE? -1: dp[dst][K];
    }
}
  1. 二维区域和检索 - 矩阵不可变(304题)
class NumMatrix {

    private int[][] dp;

    public NumMatrix(int[][] matrix) {
        if (matrix.length == 0 || matrix[0].length == 0) return;
        dp = new int[matrix.length + 1][matrix[0].length + 1];
        for (int r = 0; r < matrix.length; r++) {
            for (int c = 0; c < matrix[0].length; c++) {
                dp[r + 1][c + 1] = dp[r + 1][c] + dp[r][c + 1] + matrix[r][c] - dp[r][c];
            }
        }
    }

    public int sumRegion(int row1, int col1, int row2, int col2) {
       return dp[row2+1][col2+1]-dp[row2+1][col1]-dp[row1][col2+1]+dp[row1][col1];
    }
}
  1. 矩阵区域和(1314题)

在这里插入图片描述

class Solution {
    public int[][] matrixBlockSum(int[][] mat, int K) {
        int[][] dp =new int[mat.length+1][mat[0].length+1];
        for(int i=0;i<mat.length;i++){
            for (int j=0;j<mat[0].length;j++){
                dp[i+1][j+1]=dp[i+1][j]+dp[i][j+1]+mat[i][j]-dp[i][j];
            }
        }
        int[][] res=new int[mat.length][mat[0].length];
        
        for(int i=0;i<mat.length;i++){
            for (int j=0;j<mat[0].length;j++){
                int topLeft_i=Math.max(i-K,0);
                int topLeft_j=Math.max(j-K,0);
                int bottomRight_i= Math.min(i + K, mat.length-1);
                int bottomRight_j=Math.min(j + K, mat[0].length-1);
                res[i][j]=dp[bottomRight_i+1][bottomRight_j+1]-dp[bottomRight_i+1][topLeft_j]-dp[topLeft_i][bottomRight_j+1]+dp[topLeft_i][topLeft_j];
            }
        }
        return res;
    }
}
  1. 不同路径(62题,63相似)
    在这里插入图片描述
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 j=0;j<n;j++){
            dp[0][j]=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];
    }
}
  1. 不同的二叉搜索树
    在这里插入图片描述
class Solution {
    public int numTrees(int n) {
        if(n<=2){
            return n;
        }
        int[] dp=new int[n+1];
        dp[0]=1;dp[1]=1;dp[2]=2;
        for (int i=3;i<=n;i++){
            int index=0;
            while (index<i){
                dp[i]+=dp[index]*dp[i-1-index];
                index++;
            }
        }
        return dp[n];
    }
}
  1. 最长公共子串
public class Solution {
    public String LCS (String str1, String str2) {
        if(str1.length() == 0 || str2.length() == 0){
            return "-1";
        }
        char[] s1 = str1.toCharArray();
        char[] s2 = str2.toCharArray();
        int max = 0;   //记录最大长度
        int endIndex = -1;  //记录最大子串末尾的下标
        
        int[][] dp = new int[s1.length][s2.length];
        for (int i = 0; i < s1.length; i++) {
            for (int j = 0; j < s2.length; j++) {
                if(i==0 || j==0) {
                    dp[i][j] = s1[i] == s2[j] ? 1: 0;
                } else {
                    if(s1[i] == s2[j]) {
                        dp[i][j] = dp[i-1] [j-1] + 1;
                    }
                }
                if(dp[i][j] > max) {
                    max = dp[i][j];
                    endIndex = i;
                }
            }
        }

        return endIndex==-1 ? "-1" : str1.substring(endIndex-max+1, endIndex+1);
    }
}
  1. 最长公共子序列(1143题,583题、1035题可以使用)
    在这里插入图片描述
    这里的dp[i][j]表示从字符串s1的位置i到字符串s2的位置j的之前最长的公共子序列长度
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        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()];
    }
}
  1. 最长回文子串(516题)
    在这里插入图片描述
    dp[i][j]代表从i到j的最长回文子串
class Solution {
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        int[][] dp=new int[s.length()][s.length()];
        for (int i=n-1;i>=0;i--){
            dp[i][i]=1;
            for (int j=i+1;j<n;j++){
                if (s.charAt(i)==s.charAt(j)){
                    dp[i][j] = dp[i+1][j-1]+2;
                }else {
                    dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);
                }
            }
        }
        return dp[0][n-1];
    }
}
  1. 回文子串
    在这里插入图片描述
    dp[i][j]表示从i到j的字符串是否为回文字符串,当i和j字符相等时,分为三种情况,一种是i=j时一定是回文,一种是j=i+1时一定是回文,最后一种基于dp[i+1][j-1]来判断
class Solution {
    public int countSubstrings(String s) {
        int n = s.length();
        boolean[][] dp=new boolean[s.length()][s.length()];
        int ans = 0;
        for (int i=n-1;i>=0;i--){
            for (int j=i;j<n;j++){
                if (s.charAt(i)==s.charAt(j)  && (j - i <= 1 || dp[i + 1][j - 1])){
                    dp[i][j] = true;
                    ans++;
                }
            }
        }
        return ans;
    }
}
  1. 编辑距离(72题)
    在这里插入图片描述

这里的dp数组代表字符串s1的前i个字符和字符串s2的前j个字符的最小编辑距离,然后比较当前两个字母,如果相同则等于dp[i-1][j-1],不同则为dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]的最小值。分别代表从s1中插入

class Solution {
    public int minDistance(String word1, String word2) {
        int len1=word1.length();
        int len2=word2.length();
        int[][] dp=new int[len1+1][len2+1];
        for(int i=1; i<=len1; i++){
            dp[i][0] = i;
        }
        for(int i=1; i<=len2; i++){
            dp[0][i] = i;
        }
        for(int i=1;i<=len1;i++){
            char c = word1.charAt(i-1);
            for(int j=1;j<=len2;j++){
                if(c==word2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    dp[i][j]=1+Math.min(Math.min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1]);
                }
            }
        }
        return dp[len1][len2];
    }
}
  1. 不同的子序和(115题)
    在这里插入图片描述

这里的dp表示字符串t的前j位在s的前i位中出现的次数

class Solution {
    public int numDistinct(String s, String t) {
        int m = s.length(),n=t.length();
        if (m<n) return 0;
        int[][] dp=new int[m+1][n+1];
        for (int i=0;i<=m;i++){
            dp[i][0]=1;
        }
        for (int i=1;i<=m;i++){
            for (int j=1;j<=n;j++){
                if (s.charAt(i-1)==t.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
                }else {
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        return dp[m][n];
    }
}
  1. 整数拆分(343题)

此题贪心算法更快

class Solution {
    public int integerBreak(int n) {
        int[] dp = new int[n + 1];
        dp[2]=1;
        for (int i = 3; i <= n; i++) {
            for (int j = 1; j < i; j++) {
                dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
            }
        }
        return dp[n];
    }
}

还在不断增加经典题目

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值