速通子序列问题(动态规划一网打尽!)

引言

阅读完本篇文章,你可以在力扣顺便解决以下题目:

300. 最长递增子序列 1143. 最长公共子序列 1035. 不相交的线
674. 最长连续递增序列 718. 最长重复子数组 53. 最大子序和
392. 判断子序列 115. 不同的子序列 583. 两个字符串的删除操作
72. 编辑距离 647. 回文子串 516. 最长回文子序列

原图链接:https://www.processon.com/view/link/67209a676b5a4a4adda5922c?cid=66c30d46fb35b76d02e00e5b
在这里插入图片描述


300. 最长递增子序列(中等)

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int lengthOfLIS(int[] nums) {
    
    
        if(nums.length <= 1) return nums.length;
        int n = nums.length;
        int res = 0;
        // dp[i]表示以nums[i]结尾的最长递增子序列的长度
        int[] dp = new int[n];

        for(int i = 0;i<n;i++){
    
    
            dp[i] = 1;
        }

        for(int i = 1;i<n;i++){
    
    
            for(int j = 0;j<i;j++){
    
    
                if(nums[i] > nums[j]){
    
    
                    dp[i] = Math.max(dp[i],dp[j]+1);
                }
                res = Math.max(res,dp[i]);
            }
        }
        return res;
    }
}

1143. 最长公共子序列(中等)

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int longestCommonSubsequence(String text1, String text2) {
    
    
        // dp[i][j]表示长度为i-1的字符串text1与长度j-1的字符串text2的最长公共子序列
        int[][] dp = new int[text1.length()+1][text2.length()+1];
        int res = 0;

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

1035. 不相交的线(中等)

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
    
    
        // 跟 1143 题如出一辙
        // dp[i][j]表示长度为i-1的数组nums1与长度j-1的数组nums2的最大连线数
        int[][] dp = new int[nums1.length+1][nums2.length+1];
        int res = 0;

        for(int i=1;i<=nums1.length;i++){
    
    
            for(int j=1;j<=nums2.length;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[nums1.length][nums2.length];
    }
}

674. 最长连续递增序列(中等)

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int findLengthOfLCIS(int[] nums) {
    
    
        if(nums.length == 0) return 0;
        int n = nums.length;
        int res = 1;
        // dp[i]:以下标i为结尾的连续递增的子序列长度为dp[i]。
        int[] dp = new int[n];
        // 初始化
        Arrays.fill(dp,1);

        for(int i = 1;i<n;i++){
    
    
            if(nums[i] > nums[i-1]){
    
    
                dp[i] = dp[i-1] + 1;
            }
            res = Math.max(res,dp[i]);
        }

        return res;
    }
}

718. 最长重复子数组(中等)

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int findLength(int[] nums1, int[] nums2) {
    
    
        int m = nums1.length;
        int n = nums2.length;
        int res = 0;
        // dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]
        int[][] dp = new int[m+1][n+1];

        for(int i = 1;i<=m;i++){
    
    
            for(int j = 1;j<=n;j++){
    
    
                if(nums1[i-1] == nums2[j-1]){
    
    
                    dp[i][j] = dp[i-1][j-1] + 1;
                }
                res = Math.max(res,dp[i][j]);
            }
        }

        return res;
    }
}

53. 最大子序和(中等)

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int maxSubArray(int[] nums) {
    
    
        int n = nums.length;
        int res = nums[0];
        // dp[i]:包括下标i(以nums[i]为结尾)的最大连续子数组和为dp[i]。
        int[] dp = new int[n];
        dp[0] = nums[0];

        for(int i = 1;i<n;i++){
    
    
        	// 这里有点东西啊。。。
            dp[i] = Math.max(nums[i],dp[i-1] + nums[i]);
            res = Math.max(res,dp[i]);
        }

        return res;

    }
}

392. 判断子序列(简单)

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public boolean isSubsequence(String s, String t) {
    
    
        if(s.length() > t.length()) return false;
        // dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]
        int[][] dp = new int[s.length()+1][t.length()+1];

        for(int i=1;i<=s.length();i++){
    
    
            for(int j=1;j<=t.length();j++){
    
    
                if(s.charAt(i-1) == t.charAt(j-1)) {
    
    
                    dp[i][j] = dp[i-1][j-1] + 1; 
                }else {
    
    
                    dp[i][j] = dp[i][j-1];
                }
            }
        }

        return dp[s.length()][t.length()] == s.length();
    }
}

115. 不同的子序列(困难)

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int numDistinct(String s, String t) {
    
    
        int s1 = s.length();
        int t1 = t.length();
        // 其实就稍微麻烦了一点,细心一点也很简单
        // dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。
        int[][] dp = new int[s1+1][t1+1];

        // dp[i][0] 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数。
        // 那么dp[i][0]一定都是1,因为也就是把以i-1为结尾的s,删除所有元素,出现空字符串的个数就是1。
        for(int i=0;i<s1;i++) dp[i][0] = 1;

        for(int i=1;i<=s1;i++){
    
    
            for(int j=1;j<=t1;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[s1][t1];
    }
}

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

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int minDistance(String word1, String word2) {
    
    
        int s1 = word1.length();
        int s2 = word2.length();
        // dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数
        int[][] dp = new int[s1+1][s2+1];

        for(int i = 0;i<=s1;i++){
    
    
            dp[i][0] = i;
        }
        for(int j = 0;j<=s2;j++){
    
    
            dp[0][j] = j;
        }

        for(int i = 1;i<=s1;i++){
    
    
            for(int j = 1;j<=s2;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,dp[i][j-1] + 1);
                }
            }
        }
        return dp[s1][s2];
    }
}

72. 编辑距离

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int minDistance(String word1, String word2) {
    
    
        // dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]
        int[][] dp = new int[word1.length()+1][word2.length()+1];

        for(int i=0;i<=word1.length();i++) dp[i][0] = i;
        for(int j=1;j<=word2.length();j++) dp[0][j] = j;

        for(int i = 1;i<=word1.length();i++){
    
    
            for(int j = 1;j<=word2.length();j++){
    
    
                if(word1.charAt(i-1) == word2.charAt(j-1)){
    
    
                    dp[i][j] = dp[i-1][j-1];
                }else {
    
    
                    // 只需要一次替换的操作,就可以让 word1[i - 1] 和 word2[j - 1] 相同
                    // 所以 dp[i][j] = dp[i - 1][j - 1] + 1
                    dp[i][j] = Math.min(dp[i-1][j-1],Math.min(dp[i-1][j],dp[i][j-1])) + 1;
                }
            }
        }

        return dp[word1.length()][word2.length()];
    }
}

647. 回文子串

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int countSubstrings(String s) {
    
    
        // dp[i][j]:表示区间范围[i,j]的子串是否是回文子串,如果是dp[i][j]为true,否则为false
        boolean[][] dp = new boolean[s.length()][s.length()];
        int res = 0;

        // 从下往上,从左到右遍历dp[i+1][j-1] -> dp[i][j]
        for(int i=s.length()-1;i>=0;i--){
    
    
            for(int j=i;j<s.length();j++){
    
    
                if(s.charAt(i) == s.charAt(j)){
    
    
                    // 情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
                    // 情况二:下标i 与 j相差为1,例如aa,也是回文子串
                    if(j-i <= 1){
    
    
                        res++;
                        dp[i][j] = true;
                    // 情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看
                    // i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,
                    // 这个区间是不是回文就看dp[i + 1][j - 1]是否为true
                    } else if(dp[i+1][j-1]){
    
    
                        res++;
                        dp[i][j] = true;
                    }
                }
            }
        }

        return res;
    }
}

516. 最长回文子序列

在这里插入图片描述

☘️代码实现

class Solution {
    
    
    public int longestPalindromeSubseq(String s) {
    
    
        // dp[i][j]:表示字符串s在[i,j]范围内最长的回文子序列的长度
        int[][] dp = new int[s.length()][s.length()];

        for(int i = 0;i<s.length();i++){
    
    
            dp[i][i] = 1;
        }
        for(int i = s.length()-1;i>=0;i--){
    
    
            for(int j = i+1;j<s.length();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][s.length()-1];
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_74199893/article/details/142797470