【39】(动态规划——子序列解题模板) 最长递增子序列 | 最长回文子序列(LC 300 | 516)

动态规划——子序列解题模板

1、一维的 dp 数组

模板:

int n = array.length;
int[] dp = new int[n];

for (int i = 1; i < n; i++) {
    
    
    for (int j = 0; j < i; j++) {
    
    
        dp[i] = 最值(dp[i], dp[j] + ...)
    }
}

dp[i]的含义: 在子数组array[0…i]中,以array[i]结尾的目标子序列的长度是dp[i]。(类似如此)

例子:最长递增子序列

问题描述

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

解题思路

定义dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度,那么要求dp[i],则需要先求出max(dp[1],dp[2],…,dp[i-1]),假设max(dp[1],dp[2],…,dp[i-1]) = dp[j] , 则如果nums[i] > nums[j] ,则dp[i] = dp[j] + 1,否则dp[i]保持原值不变。

代码实现

class Solution {
    
    
    public int lengthOfLIS(int[] nums) {
    
    
        int n = nums.length;//求出数组元素个数
        if(n == 0) //若数组为空,返回0
            return 0;
        int dp[] = new int[n];//dp[i]表示以nums[i]结尾的最大递增子序列长度
        int result = -1;
        for(int i=0;i<n;i++){
    
    
            dp[i] = 1; //初始都为1
            for(int j=0;j<i;j++){
    
    //dp[0]开始
                if(nums[i]>nums[j])//若nums[i]>nums[j]则dp[i]可以为dp[j]+1,否则对dp[i]不做处理
                    dp[i] = Math.max(dp[i],dp[j]+1);
            }
            result = Math.max(dp[i],result);
        }
        return result;
    }   
}

时间复杂度:O(n^2)
空间复杂度:O(n)

2、二维的 dp 数组

模板:

int n = arr.length;
int[][] dp = new dp[n][n];

for (int i = 0; i < n; i++) {
    
    
    for (int j = 1; j < n; j++) {
    
    
        if (arr[i] == arr[j]) 
            dp[i][j] = dp[i][j] + ...
        else
            dp[i][j] = 最值(...)
    }
}

dp[i][j]的含义:

  • 涉及两个字符串/数组时:在子数组arr1[0…i]和子数组arr2[0…j]中,我们要求的子序列长度为dp[i][j]。例子:编辑距离、最长公共子序列…
  • 只涉及一个字符串/数组时:在子数组array[i…j]中,我们要求的子序列的长度为dp[i][j]。例子:最长回文子序列…

例子:最长回文子序列

问题描述

给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。

解题思路

定义dp[i][j]为子串s[i,…,j]中的最长回文子序列长度,假设此时已知dp[i+1][j-1],则若s[i]==s[j],则dp[i][j] = dp[i+1][j-1] + 2;否则等于max(dp[i+1][j],dp[i][j-1])。

代码实现

class Solution {
    
    
    public int longestPalindromeSubseq(String s) {
    
    
        int n = s.length();
        if(n == 0) return 0;
        int dp[][] = new int[n][n];
        for(int i=n-1;i>=0;i--){
    
    
            dp[i][i] = 1;// i==j时回文串长度为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];
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43424037/article/details/114230672