动态规划算法——40道leetcode实例入门到熟练

news2024/10/6 6:51:56

目录

  • t0.解题五部曲
  • 1.基础入门题目
      • 1.509. 斐波那契数
      • 2.70. 爬楼梯
      • 3.746. 使用最小花费爬楼梯
      • 4.62. 不同路径
      • 5.63. 不同路径 II
      • 6.343. 整数拆分
      • 7.96. 不同的二叉搜索树
  • 2.背包问题
    • 1.01背包(二维数组实现)
    • 2.01背包(滚动数组实现)
      • 1.416. 分割等和子集
      • 2.1049. 最后一块石头的重量 II
      • *3.494. 目标和
      • 4.474. 一和零
    • 2.完全背包
      • 1.518. 零钱兑换 II
      • 2.377. 组合总和 Ⅳ
      • 3.322. 零钱兑换
      • 4.279. 完全平方数
      • *5.139. 单词拆分
  • 3.打家劫舍
      • 1.198. 打家劫舍
      • 2.213. 打家劫舍 II
      • 3.337. 打家劫舍 III
  • 4.股票问题
      • 1.121. 买卖股票的最佳时机
      • 2.122. 买卖股票的最佳时机 II
      • 3.123. 买卖股票的最佳时机 III
      • 4.188. 买卖股票的最佳时机 IV
      • 5.309. 最佳买卖股票时机含冷冻期
      • 6.714. 买卖股票的最佳时机含手续费
  • 5.子序列问题
    • 1.子序列(不连续)
      • 1.300. 最长递增子序列
      • 2.1143. 最长公共子序列
      • 3.1035. 不相交的线
    • 2.子序列(连续)
      • 1.674. 最长连续递增序列
      • *2.718. 最长重复子数组
      • 3.53. 最大子数组和
    • 3.编辑距离
      • 1.392. 判断子序列
      • 2.115. 不同的子序列
      • 3.583. 两个字符串的删除操作
      • 4.72. 编辑距离
    • 4.回文
      • 1.647. 回文子串
      • 2.516. 最长回文子序列

t0.解题五部曲

1. 确定dp数组(dp table)以及下标的含义
2. 确定递推公式
3. dp数组如何初始化
4. 确定遍历顺序
5. 举例推导dp数组

1.基础入门题目

1.509. 斐波那契数

链接: 509. 斐波那契数
在这里插入图片描述

class Solution {
    public int fib(int n) {
        if(n<=1){
            return n;
        }
        int arr[]=new int[n+1];
        arr[0]=1;
        arr[1]=1;
        for(int i=2;i<=n;i++){
            arr[i]=arr[i-2]+arr[i-1];
        }
        return arr[n-1];
    }
}
class Solution {
    public int fib(int n) {
        if(n<=1){
            return n;
        }
        int arr0=0;
        int arr1=1;
        for(int i=2;i<=n;i++){
            int sum=arr0+arr1;
            arr0=arr1;
            arr1=sum;
        }
        return arr1;
    }
}

2.70. 爬楼梯

链接: 70. 爬楼梯
在这里插入图片描述

class Solution {
    public int climbStairs(int n) {
        if(n<=2){
            return n;
        }
        int dp[]=new int[n+1];
        dp[1]=1;
        dp[2]=2;
        for(int i=3;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
}

3.746. 使用最小花费爬楼梯

链接: 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];
    }
}

4.62. 不同路径

链接: 62. 不同路径
在这里插入图片描述

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 i=0;i<n;i++){
            dp[0][i]=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];
    }
}

5.63. 不同路径 II

在这里插入图片描述

链接: 63. 不同路径 II

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m=obstacleGrid.length;
        int n=obstacleGrid[0].length;
        if(obstacleGrid[m-1][n-1]==1||obstacleGrid[0][0]==1){
            return 0;//当start位置和finish位置有障碍时直接返回0
        }
        int dp[][]=new int[m][n];//从start每一个坐标点有多少条不同的路径
        for(int i=0;i<m&&obstacleGrid[i][0]==0;i++){
            dp[i][0]=1;//满足条件初始化第一列,若有障碍后面的dp都为0
        }
        for(int i=0;i<n&&obstacleGrid[0][i]==0;i++){
            dp[0][i]=1;//满足条件初始化第一行,若有障碍后面的dp都为0
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                if(obstacleGrid[i][j]==0){
                    dp[i][j]=dp[i-1][j]+dp[i][j-1];
                }
            }
        }
        return dp[m-1][n-1];
    }
}
            

6.343. 整数拆分

链接: 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/2;j++){

                dp[i]=Math.max(dp[i],Math.max(j*dp[i-j],j*(i-j)));

            }

        }
        return dp[n];
    }
}

7.96. 不同的二叉搜索树

链接: 96. 不同的二叉搜索树
在这里插入图片描述

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

2.背包问题

1.01背包(二维数组实现)

1.dp[i][j]数组含义:dp[i][j] 表⽰从下标为[0-i]的物品⾥任意取,放进容量为j的背包,价值总和最⼤是多少。

2.递推方程:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

01背包问题Java代码

public class Knapsack_problem01 {
    //01背包问题
    public static void main(String[] args) {
        System.out.println("背包最大价值"+knapsack());
    }
    //01背包
    //dp[i][j]数组含义:dp[i][j] 表⽰从下标为[0-i]的物品⾥任意取,
    //放进容量为j的背包,价值总和最⼤是多少。
    public static int knapsack(){
        int wight[]={1,3,4};
        int value[]={15,20,30};
        int bagW=4;
        int [][]dp=new int[wight.length][bagW+1];

        for (int i = bagW; i >= wight[0]; i--) {//初始化dp
            dp[0][i]=value[0];
        }
        //打印初始化后的dp数组
        System.out.println("=====初始化后的dp=====");
        printDP(dp);

//        for(int i=1;i<=bagW;i++){//先遍历背包容量
//            for (int j = 1; j < wight.length; j++){//遍历物品,wight数组的大小就是物品个数
//                if(i-wight[j]>=0)
//                dp[j][i]=Math.max(dp[j-1][i],(dp[j-1][i-wight[j]]+value[j]));
//            }
//        }
        for(int i=1;i<wight.length;i++){//先遍历物品,wight数组的大小就是物品个数
            for (int j = 1; j <= bagW; j++){//遍历背包
                if(j-wight[i]>=0)
                    dp[i][j]=Math.max(dp[i-1][j],(dp[i-1][j-wight[i]]+value[i]));
            }
        }
        //打印dp数组
        System.out.println("=====递推后的·dp=====");
        printDP(dp);

        return dp[wight.length-1][bagW];
    }

    //打印dp数组
    public static void printDP(int [][]dp){
        for (int i = 0; i < dp.length; i++) {
            for (int j = 0; j < dp[0].length; j++) {
                System.out.print(dp[i][j]+" ");
            }
            System.out.println();
        }
    }

}

在这里插入图片描述

2.01背包(滚动数组实现)

  1. 在使⽤⼆维数组的时候,递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] +value[i]);
  2. 其实可以发现如果把dp[i - 1]那⼀层拷贝到dp[i]上,表达式完全可以是:dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]); 于其把dp[i -1]这⼀层拷贝到dp[i]上,不如只⽤⼀个⼀维数组了,只⽤dp[j](⼀维数组,也 可以理解是⼀个滚动数组)。

1. 确定dp数组的定义

在⼀维dp数组中,dp[j]表⽰:容量为j的背包,所背的物品价值可以最⼤为dp[j]。

2.递推公式

dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

java代码

//01背包(一维滚动数组实现)
    //在⼀维dp数组中,dp[j]表⽰:容量为j的背包,所背的物品价值可以最⼤为dp[j]。
    public static int knapsack02(){
        int weight[]={1,3,4};
        int value[]={15,20,30};
        int bagW=4;
        int []dp=new int[bagW+1];//默认初始化为0

        for(int i = 0; i < weight.length; i++) { // 遍历物品
            for(int j = bagW; j >= weight[i]; j--) { // 遍历背包容量
                dp[j] = Math.max(dp[j], dp[j-weight[i]]+value[i]);
            }
        }
        return dp[bagW];
    }

在这里插入图片描述

1.416. 分割等和子集

链接: 416. 分割等和子集
在这里插入图片描述

class Solution {
    public boolean canPartition(int[] nums) {
        int target=0;
        for(int i=0;i<nums.length;i++){
            target+=nums[i];
        }
        if(target%2!=0){
            return false;
        }
        target=target/2;
        int dp[]=new int[target+1];//默认初始化为0
        for(int i=0;i<nums.length;i++){//先遍历物品
            for(int j=target;j>=nums[i];j--){//倒序遍历背包,确保每个物品只能进入一次
                dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]);
            }
        }
        if(dp[target]==target){
            return true;
        }
        return false;

    }
}

2.1049. 最后一块石头的重量 II

链接: 1049. 最后一块石头的重量 II
在这里插入图片描述

class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum=0;
        for(int i=0;i<stones.length;i++){
            sum+=stones[i];
        }
        int target=sum/2;//将stones数组一分为二,找到重量最接近target的dp数组
        int dp[]=new int[target+1];//默认初始化为0
        for(int i=0;i<stones.length;i++){//先遍历石头
            for(int j=target;j>=stones[i];j--){//再逆序遍历背包
                dp[j]=Math.max(dp[j],dp[j-stones[i]]+stones[i]);
            }
        }
        int min_Weight=(sum-dp[target])-dp[target];//一分为二的石头相减得到最小重量
        return min_Weight;
    }
}

*3.494. 目标和

链接: 494. 目标和
在这里插入图片描述

在这里插入图片描述

class Solution {
    public int findTargetSumWays(int[] nums, int target) {
        int sum = 0;
        for (int i = 0; i < nums.length; i++) 
            sum += nums[i];

        if(Math.abs(target)>sum){//如果target的绝对值大于sum,此时没有方案
            return 0;
        }

        if ((target + sum) % 2 == 1) 
            return 0; // 此时没有⽅案

        int bagSize=(sum+target)/2;
        int dp[]=new int[bagSize+1];
        dp[0]=1;
        for(int i=0;i<nums.length;i++){
            for(int j=bagSize;j>=nums[i];j--){
                dp[j]+=dp[j-nums[i]];
            }
        }
        return dp[bagSize];
    }
}

4.474. 一和零

链接: 474. 一和零
在这里插入图片描述

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int dp[][]=new int[m+1][n+1];//默认初始化为0;

        for(String str:strs){
            int num1=0;int num0=0;
            for(char c:str.toCharArray()){
                if(c=='1'){
                    num1++;
                }else{
                    num0++;
                }
            }
            for(int i=m;i>=num0;i--){
                for(int j=n;j>=num1;j--){
                    dp[i][j]=Math.max(dp[i][j],dp[i-num0][j-num1]+1);
                }
            }
        }
        return dp[m][n];

    }
}

2.完全背包

public class CompleteBackpack {
    //完全背包问题
    public static void main(String[] args) {
        System.out.println(test_CompletePack());
    }
    // 先遍历物品,在遍历背包
    public static int test_CompletePack() {
        int []weight = {1, 3, 4};
        int []value = {15, 20, 30};
        int bagWeight = 4;
        int dp[]=new int[bagWeight + 1];
        for(int i = 0; i < weight.length; i++) { // 遍历物品
            for(int j = weight[i]; j <= bagWeight; j++) { // 遍历背包容量
                //正序遍历,每个物品可以选多次
                dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
            }
        }
        return dp[bagWeight];
    }
}

1.518. 零钱兑换 II

链接: 518. 零钱兑换 II
在这里插入图片描述

class Solution {
    public int change(int amount, int[] coins) {
        int n=coins.length;
        int dp[]=new int[amount+1];//默认初始化为0
        dp[0]=1;//初始化不放入物品的方式有一种
        for(int i=0;i<n;i++){
            for(int j=coins[i];j<=amount;j++){
                dp[j]+=dp[j-coins[i]];
            }
        }
        return dp[amount];
    }
}

2.377. 组合总和 Ⅳ

链接: 377. 组合总和 Ⅳ
在这里插入图片描述

class Solution {
    public int combinationSum4(int[] nums, int target) {
        int dp[]=new int[target+1];
        dp[0]=1;
        for(int i=0;i<=target;i++){
            for(int j=0;j<nums.length;j++){
                if (i >= nums[j] )
                    dp[i]+=dp[i-nums[j]];
            }
        }
        return dp[target];
    }
}

3.322. 零钱兑换

链接: 322. 零钱兑换
在这里插入图片描述

class Solution {
    public int coinChange(int[] coins, int amount) {
        int n=coins.length;
        int dp[]=new int[amount+1];//默认初始化为0
        dp[0]=0;//先凑⾜总⾦额为0所需钱币的个数⼀定是0
        for(int i=1;i<=amount;i++){
            dp[i]=Integer.MAX_VALUE;
        }
        for(int i=0;i<n;i++){
            for(int j=coins[i];j<=amount;j++){
                if(dp[j-coins[i]]!=Integer.MAX_VALUE)
                dp[j]=Math.min(dp[j-coins[i]]+1,dp[j]);
            }
        }
        if(dp[amount]==Integer.MAX_VALUE)
            return -1;
        return dp[amount];
    }
}

4.279. 完全平方数

链接: 279. 完全平方数
在这里插入图片描述

class Solution {
    public int numSquares(int n) {
        int dp[]=new int[n+1];
        dp[0]=0;
        for(int i=1;i<=n;i++){
            dp[i]=Integer.MAX_VALUE;
        }
        for(int i=0;i*i<=n;i++){
            for(int j=i*i;j<=n;j++){
                if(dp[j-i*i]!=Integer.MAX_VALUE)
                    dp[j]=Math.min(dp[j-i*i]+1,dp[j]);
            }
        }
        return dp[n];
    }
}

*5.139. 单词拆分

链接: 139. 单词拆分
在这里插入图片描述

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

3.打家劫舍

1.198. 打家劫舍

链接: 198. 打家劫舍
在这里插入图片描述

class Solution {
    public int rob(int[] nums) {
        int n=nums.length;
        if(n<=1){
            return nums[0];
        }
        int dp[]=new int[n];//默认初始化为0
        dp[0]=nums[0];
        dp[1]=Math.max(nums[0],nums[1]);
        for(int i=2;i<n;i++){
            dp[i]=Math.max((nums[i]+dp[i-2]),dp[i-1]);
        }
        return dp[n-1];
    }
}

2.213. 打家劫舍 II

链接: 213. 打家劫舍 II
在这里插入图片描述

class Solution {
    public int rob(int[] nums) {
        int n=nums.length;
        if(n<=1){
            return nums[0];
        }else if(n==2){
            return Math.max(nums[0],nums[1]);
        }
        return Math.max(fun(nums,0,n-1),fun(nums,1,n));
    }
     public int fun(int[] nums,int i,int n) {
        int dp[]=new int[n];//默认初始化为0
        dp[i]=nums[i];
        dp[i+1]=Math.max(nums[i],nums[i+1]);
        for(int j=i+2;j<n;j++){
            dp[j]=Math.max((nums[j]+dp[j-2]),dp[j-1]);
        }
        return dp[n-1];
    }
}

3.337. 打家劫舍 III

链接: 337. 打家劫舍 III
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int rob(TreeNode root) {
        int result[] = robTree(root);
        return Math.max(result[0], result[1]);
    }
    // ⻓度为2的数组,0:不偷,1:偷
    int[] robTree(TreeNode cur) {
        if (cur == null) 
            return new int[]{0, 0};
        int left[] = robTree(cur.left);
        int right[] = robTree(cur.right);
        // 偷cur
        int val1 = cur.val + left[0] + right[0];
        // 不偷cur
        int val2 = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        return new int[]{val2, val1};
    }
}

4.股票问题

1.121. 买卖股票的最佳时机

链接: 121. 买卖股票的最佳时机
在这里插入图片描述

class Solution {
    public int maxProfit(int[] prices) {
        int n=prices.length;
        if(n==0){
            return 0;
        }
        int [][]dp=new int[n][2];
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        for(int i=1;i<n;i++){
            dp[i][0]=Math.max(dp[i-1][0],-prices[i]);
            dp[i][1]=Math.max(dp[i-1][1],prices[i]+dp[i-1][0]);
        }
        return dp[n-1][1];
    }
}

2.122. 买卖股票的最佳时机 II

链接: 122. 买卖股票的最佳时机 II

class Solution {
    public int maxProfit(int[] prices) {
        int n=prices.length;
        if(n==0){
            return 0;
        }
        int [][]dp=new int[n][2];
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        for(int i=1;i<n;i++){
            dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]-prices[i]);//和1唯一不同
            dp[i][1]=Math.max(dp[i-1][1],prices[i]+dp[i-1][0]);
        }
        return dp[n-1][1];
    }
}

3.123. 买卖股票的最佳时机 III

链接: 123. 买卖股票的最佳时机 III
在这里插入图片描述


class Solution {
    public int maxProfit(int[] prices) {
        int n=prices.length;
        if(n==0){
            return 0;
        }
        int [][]dp=new int[n][4];
        dp[0][0]=-prices[0];//第一次持有
        dp[0][1]=0;//第一次不持有
        dp[0][2]=-prices[0];//第二次持有
        dp[0][3]=0;//第二次不持有
        for(int i=1;i<n;i++){
            dp[i][0]=Math.max(dp[i-1][0],-prices[i]);
            dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
            dp[i][2]=Math.max(dp[i-1][2],dp[i-1][1]-prices[i]);
            dp[i][3]=Math.max(dp[i-1][3],dp[i-1][2]+prices[i]);
        }
        return dp[n-1][3];
    }
}

4.188. 买卖股票的最佳时机 IV

链接: 188. 买卖股票的最佳时机 IV
在这里插入图片描述

class Solution {
    public int maxProfit(int k, int[] prices) {
        int n=prices.length;
        if(n==0)
            return 0;
        int [][]dp=new int[n][2*k+1];//初始化默认为0
        for(int j=1;j<2*k;j+=2){
            dp[0][j]=-prices[0];//第j次持有
        }
        for(int i=1;i<n;i++){
            for(int j=0;j<2*k;j+=2){
                dp[i][j+1]=Math.max(dp[i-1][j+1],dp[i-1][j]-prices[i]);
                dp[i][j+2]=Math.max(dp[i-1][j+2],dp[i-1][j+1]+prices[i]);
            }
        }
        return dp[n-1][2*k];
    }
}

5.309. 最佳买卖股票时机含冷冻期

链接: 309. 最佳买卖股票时机含冷冻期
在这里插入图片描述

class Solution {
    public int maxProfit(int[] prices) {
        int n=prices.length;
        if(n==0){
            return 0;
        }
        int [][]dp=new int[n][4];
        dp[0][0]=-prices[0];//持股
        dp[0][1]=0;//保持卖出股
        dp[0][2]=0;//卖出股
        dp[0][3]=0;//冷冻期
        for(int i=1;i<n;i++){
            dp[i][0]=Math.max(dp[i-1][0],Math.max(dp[i-1][1],dp[i-1][3])-prices[i]);
            dp[i][1]=Math.max(dp[i-1][1],dp[i-1][3]);
            dp[i][2]=dp[i-1][0]+prices[i];
            dp[i][3]=dp[i-1][2];
        }
        return Math.max(dp[n - 1][3],Math.max(dp[n - 1][1], dp[n - 1][2]));
    }
}

6.714. 买卖股票的最佳时机含手续费

链接: 714. 买卖股票的最佳时机含手续费
在这里插入图片描述

class Solution {
    public int maxProfit(int[] prices, int fee) {
        int n=prices.length;
        if(n==0){
            return 0;
        }
        int [][]dp=new int[n][2];
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        for(int i=1;i<n;i++){
            dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]-prices[i]);
            dp[i][1]=Math.max(dp[i-1][1],prices[i]+dp[i-1][0]-fee);
        }
        return dp[n-1][1];
    }
}

5.子序列问题

1.子序列(不连续)

1.300. 最长递增子序列

链接: 300. 最长递增子序列
在这里插入图片描述

class Solution {
    public int lengthOfLIS(int[] nums) {
        int n=nums.length;
        if(n<=1){
            return n;
        }
        int dp[]=new int[n];
        for(int i=0;i<n;i++){
            dp[i]=1;
        }
        int result=0;
        for(int i=1;i<n;i++){
            for(int j=0;j<i;j++){
                if(nums[i]>nums[j]){
                    dp[i]=Math.max(dp[j]+1,dp[i]);
                }
            }
            result=Math.max(result,dp[i]);
        }
        return result;
    }
}

2.1143. 最长公共子序列

链接: 1143. 最长公共子序列
在这里插入图片描述


class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        char []nums1=text1.toCharArray();
        char []nums2=text2.toCharArray();
        int n1=nums1.length;
        int n2=nums2.length;
        int dp[][]=new int[n1+1][n2+1];//默认初始化为0
        int result=0;
        for(int i=1;i<=n1;i++){
            for(int j=1;j<=n2;j++){
                if(nums1[i-1]==nums2[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[n1][n2];
    }
}

3.1035. 不相交的线

链接: 1035. 不相交的线
在这里插入图片描述


class Solution {//和上一题一摸一样,求最长公共子序列
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
        int n1=nums1.length;
        int n2=nums2.length;
        int dp[][]=new int[n1+1][n2+1];//默认初始化为0
        int result=0;
        for(int i=1;i<=n1;i++){
            for(int j=1;j<=n2;j++){
                if(nums1[i-1]==nums2[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[n1][n2];
    }
}

2.子序列(连续)

1.674. 最长连续递增序列

链接: 674. 最长连续递增序列
在这里插入图片描述

class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int n=nums.length;
        if(n<=1){
            return n;
        }
        int dp[]=new int[n];
        for(int i=0;i<n;i++){
            dp[i]=1;
        }
        int result=0;
        for(int i=1;i<n;i++){
                if(nums[i]>nums[i-1]){
                    dp[i]=dp[i-1]+1;
                }
            result=Math.max(result,dp[i]);
        }
        return result;
    }
}

*2.718. 最长重复子数组

链接: 718. 最长重复子数组
在这里插入图片描述

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int n1=nums1.length;
        int n2=nums2.length;
        int dp[][]=new int[n1+1][n2+1];//默认初始化为0
        int result=0;
        for(int i=1;i<=n1;i++){
            for(int j=1;j<=n2;j++){
                if(nums1[i-1]==nums2[j-1]){
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                result=Math.max(result,dp[i][j]);

            }
        }
        return result;
    }
}

3.53. 最大子数组和

链接: 53. 最大子数组和
在这里插入图片描述

class Solution {
    public int maxSubArray(int[] nums) {
        int n=nums.length;
        int dp[]=new int [n];
        dp[0]=nums[0];
        int result=dp[0];
        for(int i=1;i<n;i++){
            dp[i]=Math.max(dp[i-1]+nums[i],nums[i]);
            result=Math.max(dp[i],result);
        }
        return result;
    }
}

3.编辑距离

1.392. 判断子序列

链接: 392. 判断子序列
在这里插入图片描述

class Solution {
    public boolean isSubsequence(String s, String t) {
        char []nums1=s.toCharArray();
        char []nums2=t.toCharArray();
        int n1=nums1.length;
        int n2=nums2.length;
        int dp[][]=new int[n1+1][n2+1];//默认初始化为0
        for(int i=1;i<=n1;i++){
            for(int j=1;j<=n2;j++){
                if(nums1[i-1]==nums2[j-1]){
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
                    dp[i][j]=dp[i][j-1];
                }
            }
        }
        if(dp[n1][n2]==n1){
            return true;
        }
        return false;
    }
}

2.115. 不同的子序列

链接: 115. 不同的子序列
在这里插入图片描述

class Solution {
    public int numDistinct(String s, String t) {
        int n1=s.length();
        int n2=t.length();
        int [][]dp=new int[n1+1][n2+1];//默认为0
        for(int i=0;i<n1;i++){
            dp[i][0]=1;
        }

        for(int i=1;i<=n1;i++){
            for(int j=1;j<=n2;j++){
                if (j > i)
                    continue;
                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[n1][n2];
    }
}

3.583. 两个字符串的删除操作

链接: 583. 两个字符串的删除操作
在这里插入图片描述
方法一,动态规划思路解决

class Solution {
    public int minDistance(String word1, String word2) {
        int n1=word1.length();
        int n2=word2.length();
        int [][]dp=new int[n1+1][n2+1];//默认为0
        for(int i=0;i<=n1;i++){
            dp[i][0]=i;
        }
        for(int j=0;j<=n2;j++){
            dp[0][j]=j;
        }

        for(int i=1;i<=n1;i++){
            for(int j=1;j<=n2;j++){
                if(word1.charAt(i-1)==word2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    dp[i][j]=
                    Math.min(dp[i-1][j-1]+2,
                    Math.min(dp[i-1][j]+1,dp[i][j-1]+1));
                }
            }
        }
        return dp[n1][n2];
    }
}

方法二,求公共最大子序列,len1+len2-最大子序列长度即为需要删除的数目

//方法二
class Solution {
    public int minDistance(String word1, String word2) {
        int n1=word1.length();
        int n2=word2.length();
        int dp[][]=new int[n1+1][n2+1];//默认初始化为0
        int result=0;
        for(int i=1;i<=n1;i++){
            for(int j=1;j<=n2;j++){
                if(word1.charAt(i-1)==word2.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 n1+n2-2*dp[n1][n2];
    }
}

4.72. 编辑距离

链接: 72. 编辑距离
在这里插入图片描述

class Solution {
    public int minDistance(String word1, String word2) {
        int n1=word1.length();
        int n2=word2.length();
        int [][]dp=new int[n1+1][n2+1];//默认为0
        for(int i=0;i<=n1;i++){
            dp[i][0]=i;
        }
        for(int j=0;j<=n2;j++){
            dp[0][j]=j;
        }
        for(int i=1;i<=n1;i++){
            for(int j=1;j<=n2;j++){
                if(word1.charAt(i-1)==word2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    dp[i][j]=
                    Math.min(dp[i-1][j-1]+1,
                                Math.min(dp[i-1][j]+1,dp[i][j-1]+1));
                }
            }
        }
        return dp[n1][n2];
    }
}

4.回文

1.647. 回文子串

链接: 647. 回文子串
在这里插入图片描述

class Solution {
    public int countSubstrings(String s) {
        int n=s.length();
        int dp[][]=new int[n+1][n+1];
        int result=0;
        for(int i=n-1;i>=0;i--){
            for(int j=i;j<n;j++){
                if(s.charAt(i)==s.charAt(j)){
                    if(j-i<=1){
                        dp[i][j]=1;
                        result++;
                    }else if(dp[i+1][j-1]==1){
                    dp[i][j]=1;
                    result++;
                    }
                }
            }
        }
        return result;
    }
}

2.516. 最长回文子序列

链接: 516. 最长回文子序列
在这里插入图片描述

class Solution {
    public int longestPalindromeSubseq(String s) {
        int n=s.length();
        int dp[][]=new int[n+1][n+1];
        for(int i=0;i<n;i++){
            dp[i][i]=1;
        }
        for(int i=n-1;i>=0;i--){
            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];
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/496528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenPCDet系列 | 4.数据集数据加载流程

文章目录 数据加载流程0. create_kitti_infos1. __getitem__函数2. prepare_data函数3. collate_batch函数数据加载流程 这里记录一下具体用到的那些数据形式,整个kitti数据集的处理框架图如下所示: 在数据集处理到获取一个batch数据的整个流程的入口如下: # 开始迭代每…

01-微服务部署2023系列-centos安装nginx和jdk教程

centos安装nginx和jdk教程 一、centos安装nginx 0、前提:安装依赖 yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel 1、压缩包 下载nginx 选择Stable version: http://nginx.org/en/download.html 上传压缩包到…

yolov3核心网络模型

1. 改进概述 yolov3主要围绕核心网络Darknet优化进行。 yolov3的速度和map值比之前的算法优秀。 改进包含&#xff1a;网络结构、特征融合、先验框&#xff1a; V1 2, V25,V39、Softmax等。 softmax 2. 多scale方法改进与特征融合 3. 经典变换方法 预测中目标时&#xff0c…

Nacos配置管理、Fegin远程调用、Gateway服务网关

1.Nacos配置管理 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#xf…

Spring-IOC

IOC概念和原理 什么是IOC 控制反转&#xff0c;为了将系统的耦合度降低&#xff0c;把对象的创建和对象直接的调用过程权限交给Spring进行管理。 IOC底层原理 XML解析 ​ 通过Java代码解析XML配置文件或者注解得到对应的类的全路径&#xff0c;获取对应的Class类 Class clazz …

Django框架之模型查询介绍及示例

本篇文章所使用模型查询都在《Django框架之模型自定义管理器》基础上讲解查询和使用示例&#xff0c;通过看前篇可以有助于理解内容。 概述 查询集&#xff1a;从数据库获取的对象集合 查询集可以有多个过滤器 过滤器就是一个函数&#xff0c;根据所给的参数限制查询集结果 …

【Vue学习笔记5】Vue3中的响应式:ref和reactive、watchEffect和watch

所谓响应式就是界面和数据同步&#xff0c;能实现实时更新。 Vue 中用过三种响应式解决方案&#xff0c;分别是 defineProperty、Proxy 和 value setter。Vue 2 使用的方案是 defineProperty API。Vue3中使用的方案是Proxy和value setter。 1. ref和reactive vue3中实现响应…

基于docker部署ELK实战- ELK文章1

选择版本为elasticsearch:7.17.9&#xff0c;kibana:7.17.9&#xff0c;logstash:7.17.9 版本一定要一致 docker hub地址&#xff1a;https://hub.docker.com elk相关文档&#xff1a;https://www.elastic.co/guide/en/kibana/7.17 一、部署单点es 1.创建网络 因为我们还需要…

iframe嵌套grafana (前端视角)

1、grafana 启动方式 ①.grafana目录鉴赏。咱们就是直接拿到配置好的grafana。咱们暂时不涉及配置数据啥。 ①.双击grafana-server.exe &#xff0c;会出现黑色命令框。 ②.在浏览器中访问 http://localhost:3000 此时就可以看到配置好的grafana 2.前端嵌入 ①.html <…

消息队列中间件 - Docker安装RabbitMQ、AMQP协议、和主要角色

概述 不管是微服务还是分布式的系统架构中&#xff0c;消息队列中间件都是不可缺少的一个重要环节&#xff0c;主流的消息队列中间件有RabbitMQ、RocketMQ等等&#xff0c;从这篇开始详细介绍以RabbitMQ为代表的消息队列中间件。 AMQP协议 AMQP协议是一个提供统一消息服务的应…

图像处理:基于cv2.inpaint()图像修补

前言 今天我们将学习如何通过一种“修复”的方法消除旧照片中的小噪音&#xff0c;笔画等。当然&#xff0c;经过我的测试你也可以将其用于削弱混杂了其他的颜色的图像。 实验背景 大多数人家都会有一些旧的的旧化照片&#xff0c;上面有黑点&#xff0c;一些笔触等。你是否…

从零实现深度学习框架——常见学习率调整策略原理与实现

引言 本着“凡我不能创造的&#xff0c;我就不能理解”的思想&#xff0c;本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架&#xff0c;该框架类似PyTorch能实现自动求导。 &#x1f4a1;系列文章完整目录&#xff1a; &#x1f449;点此&#x1f448; 要深入理解…

day24_多线程

今日内容 零、 复习昨日 一、作业 二、线程安全的集合 三、死锁 四、线程通信 五、生产者消费者 六、线程池 零、 复习昨日 见晨考 一、作业 售卖后车票 见代码二、线程安全的类[了解] StringBuffer是线程安全的,是因为每个方法都加上synchronized,即都是同步方法 StringBuil…

【前端】前后端分离ruoyi-vue初步学习

1.了解vue基础知识。 Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org) 2.将ruoyi-vue项目拉下来&#xff0c;并成功运行。 开源项目网址&#xff1a;RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|…

《Netty》从零开始学netty源码(五十四)之PoolThreadLocalCache

PoolThreadLocalCache 前面讲到PoolThreadCache&#xff0c;它为线程提供内存缓存&#xff0c;当线程需要分配内存时可快速从其中获取&#xff0c;在Netty中用PoolThreadLocalCache来管理PoolThreadCache&#xff0c;它的数据结构如下&#xff1a; PoolThreadLocalCache相当…

【网络】UDP网络服务器简单模拟实现

【网络】UDP网络服务器简单模拟实现 文章目录 makefile服务端udpServerudpServer.ccudpServer.hpp初始化启动测试 客户端udpClientudpClient.ccudpClient.hpp初始化启动 整体代码 UDP的封装: UDP网络服务器模拟实现&#xff1a;主要分为makefile文件进行编译 UDP客户端&#xf…

Java开发 - 不知道算不算详细的分布式事务详解

前言 前日对JUC进行了一个深度总结&#xff0c;不过现在博主能记得的也不多了&#xff0c;只是这东西&#xff0c;不是看几遍写几遍就能完全记住的&#xff0c;功夫在平时&#xff0c;很多知识点都需要反复的看&#xff0c;不光要看&#xff0c;还要用&#xff0c;这样才能了解…

在CentOS上安装Jenkins并配置Docker

文章目录 步骤1 - 安装Java 11步骤2 - 安装Jenkins步骤3 - 安装Docker步骤4 - 配置Docker Cloud步骤 5 - 验证步骤 6 - 可能会遇到的问题 在本教程中&#xff0c;我们将展示如何在CentOS上安装Jenkins和Docker&#xff0c;并将它们配置在同一台机器上&#xff0c;使Jenkins能够…

《花雕学AI》WeTab+ChatGPT:让浏览器变成你的智能助手

引言&#xff1a; 浏览器是我们日常使用的最重要的工具之一&#xff0c;它可以帮助我们获取信息、娱乐、学习、工作等。但是&#xff0c;传统的浏览器往往不能满足我们的个性化需求&#xff0c;也不能给我们提供智能化的服务。那么&#xff0c;有没有一种浏览器可以让我们的体…

yoloV2细节改进

文章目录 1 v2 细节升级概述2 .网络结构特点3. 架构细节解读4. 基于聚类来选择先验框尺寸5. 偏移量计算方法6. 坐标映射与还原7 感受野8. 特征融合的改进其他知识点filter 是什么&#xff1f; 1 v2 细节升级概述 2 .网络结构特点 使用dropout&#xff0c;杀死部分神经元&#…