[39](動的計画法-サブシーケンス問題解決テンプレート)最長増加サブシーケンス|最長パリンドロームサブシーケンス(LC 300 | 516)

動的計画法-サブシーケンス問題解決テンプレート

1.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.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]の意味:

  • 2つの文字列/配列が含まれる場合:サブ配列arr1 [0 ... i]とサブ配列arr2 [0 ... j]では、必要なサブシーケンスの長さはdp [i] [です。 j]。例:編集距離、最長共通部分列...
  • 文字列/配列が1つだけ含まれている場合:サブ配列array [i ... j]では、必要なサブシーケンスの長さはdp [i] [j]です。例:最長の回文サブシーケンス..

例:最長の回文サブシーケンス

問題の説明

文字列sが与えられた場合、最長の回文サブシーケンスを見つけて、シーケンスの長さを返します。sの最大長は1000であると想定できます。

問題解決のアイデア

dp [i] [j]を、この時点でdp [i + 1] [j-1]がわかっていると仮定して、部分文字列s [i、…、j]内の最長の回文サブシーケンスの長さとして定義します。 [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