动态规划-子序列问题

300.最长递增子序列

1.dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度

2.位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。

if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);

// 注意这里不是要dp[i] 与 dp[j] + 1进行比较,而是我们要取dp[j] + 1的最大值

3. dp[i](即最长递增子序列)起始大小至少都是1.

4. 从前向后遍历

class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        Arrays.fill(dp,1);
        int res = 1;
        for(int i=1; inums[j]){
                    dp[i] = Math.max(dp[i],dp[j]+1);
                }
            }
            res = Math.max(res,dp[i]);
        }
        // 注意最长的子序列不一定是在dp[n-1]处
        // 所以需要一个res去接收最大的dp值
        return res;
    }
}

674. 最长连续递增序列

在上一题的基础上要求连续

因此就只需要与前一个比较即可

本题也可用贪心解决

class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        Arrays.fill(dp,1);
        int res = 1;
        for(int i=1; inums[i-1]){
                dp[i]=dp[i-1]+1;
            }
            res = Math.max(res,dp[i]);
        }
        return res;
    }
}

// 贪心
class Solution {
    public int findLengthOfLCIS(int[] nums) {
        int count=1;
        int res = 1;
        for(int i=1; inums[i-1]){
                count++;
            }else{
                count=1;
            }
            res = Math.max(res,count);
        }
        return res;
    }
}

718. 最长重复子数组

1.dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度。

2.当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;

3.dp[i][0] 和dp[0][j]其实都没有意义,但可以初始化为0。

4.外层for循环遍历A,内层for循环遍历B。

class Solution {
    public int findLength(int[] nums1, int[] nums2) {
        int m = nums1.length+1;
        int n= nums2.length+1;
        int res=0;
        int[][] dp = new int[m][n];
        for(int i=1; i

 1143. 最长公共子序列

1.dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]

2.递推情况如下

  • text1[i - 1] 与 text2[j - 1]相同:dp[i][j] = dp[i - 1][j - 1] + 1;
  • text1[i - 1] 与 text2[j - 1]不相同:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大

3.dp[i][0] = 0=dp[0][j]。

4.从前向后,从上到下来遍历

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int m = text1.length()+1;
        int n = text2.length()+1;
        int[][] dp = new int[m][n];
        for(int i=1; i

1035. 不相交的线

直线不能相交,就是说明在字符串A中 找到一个与字符串B相同的子序列,且这个子序列不能改变相对顺序。只要相对顺序不改变,连接相同数字的直线就不会相交。

因此,本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!

与上一题一模一样

class Solution {
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
        int m = nums1.length+1;
        int n = nums2.length+1;
        int[][] dp = new int[m][n];
        for(int i=1; i

53. 最大子数组和

1.dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]

2.dp[i] = max(dp[i - 1] + nums[i], nums[i]);

3.dp[0] = nums[0]。

4.从前向后遍历。

class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        dp[0] = nums[0];
        int res = nums[0];
        for(int i=1; i

编辑距离 

392. 判断子序列

1.dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度

2.if (s[i - 1] == t[j - 1]){dp[i][j] = dp[i - 1][j - 1] + 1;}else{dp[i][j] = dp[i][j - 1];}

注意:题目要求判断s是否是t的子序列,所以只考虑删除t[j-1],而不考虑删除s[i-1].

3.dp[i][0]=0 =dp[0][j]

4.从上到下,从左到右

class Solution {
    public boolean isSubsequence(String s, String t) {
        int m = s.length()+1;
        int n = t.length()+1;
        int[][] dp = new int[m][n];
        for(int i=1; i

115. 不同的子序列

1.dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数。

2.

  • 当s[i - 1] 与 t[j - 1]相等时
    • 用s[i - 1]来匹配,那么个数为dp[i - 1][j - 1]
    • 不用s[i - 1]来匹配,个数为dp[i - 1][j]
  • 当s[i - 1] 与 t[j - 1]不相等时
    • dp[i - 1][j]
    • 注意:题目要求的是s的子序列在t中出现的次数,所以只考虑不用s[i-1]匹配的情况,而不用考虑t[i-1].

3.

  • dp[i][0] =1:以i-1为结尾的s可以随便删除元素,出现空字符串的个数。
  • dp[0][j]=0:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数。
  • dp[0][0]=1:空字符串s,可以删除0个元素,变成空字符串t。

4.从上到下,从左到右遍历

class Solution {
    public int numDistinct(String s, String t) {
        int m =s.length()+1;
        int n = t.length()+1;
        int[][] dp = new int[m][n];
        for(int i=0; i

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

1.dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。

2.

  • 当word1[i - 1] 与 word2[j - 1]相同的时候
    • dp[i][j] = dp[i - 1][j - 1];
  • 当word1[i - 1] 与 word2[j - 1]不相同的时候,三种情况取min值
    • 删word1[i - 1],最少操作次数为dp[i - 1][j] + 1
    • 删word2[j - 1],最少操作次数为dp[i][j - 1] + 1
    • 同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2,包含于前两种情况

3.dp[i][0] = i;dp[0][j]=j

4.从上到下,从左到右遍历

class Solution {
    public int minDistance(String word1, String word2) {
        int m = word1.length()+1;
        int n = word2.length()+1;
        int[][] dp = new int[m][n];
        for(int i = 0; i 

72. 编辑距离

1.dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]

2.

  • if (word1[i - 1] == word2[j - 1])    dp[i][j] = dp[i - 1][j - 1];
  • if (word1[i - 1] != word2[j - 1])
    • word1删除一个元素,dp[i][j] = dp[i - 1][j] + 1;
    • word2删除一个元素,dp[i][j] = dp[i][j - 1] + 1;
    • word1替换word1[i - 1],使其与word2[j - 1]相同,dp[i][j] = dp[i - 1][j - 1] + 1;
    • 注意:不用考虑添加情况。word2添加一个元素,相当于word1删除一个元素

3.dp[i][0] = i;dp[0][j] = j;

4.从左到右从上到下去遍历。

class Solution {
    public int minDistance(String word1, String word2) {
        int m = word1.length()+1;
        int n = word2.length()+1;
        int[][] dp = new int[m][n];
        for(int i=0; i

647. 回文子串

判断一个子字符串(字符串下标范围[i,j])是否回文,依赖于,子字符串(下标范围[i + 1, j - 1])) 是否是回文。

1.布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,

2.

  • 当s[i]与s[j]不相等,dp[i][j]一定是false。
  • 当s[i]与s[j]相等时
    • i == j,同一个字符,当然是回文子串
    • i 与 j相差为1,也是回文子串
    • i 与 j相差大于1的时候,就看dp[i + 1][j - 1]是否为true。

3.dp[i][j]初始化为false

4.从下到上,从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的

class Solution {
    public int countSubstrings(String s) {
        int n =s.length();
        boolean [][] dp = new boolean[n][n];
        int res=0;
        for(int i = n-1; i>=0; i--){
            for(int j=i; j

516. 最长回文子序列

1.dp[i][j]:字符串s在[i, j]范围内最长的回文子序列的长度

2.

  • 如果s[i]与s[j]相同,那么dp[i][j] = dp[i + 1][j - 1] + 2;
  • 如果s[i]与s[j]不相同,下面两种情况取max值
    • 加入s[j]的回文子序列长度为dp[i + 1][j]
    • 加入s[i]的回文子序列长度为dp[i][j - 1]。

3.i==j时,dp[i[j]=1

4.从下到上遍历,从左向右遍历。

class Solution {
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        int[][] dp = new int[n][n];
        for(int i=n-1; i>=0; i--){
            dp[i][i]=1;
            for(int j=i+1; j

你可能感兴趣的:(算法题汇总,动态规划,算法)