動的計画法シリーズの「最長増加部分列」

无序整数配列が与えられた場合、最長の昇順部分列を見つけます长度

注:ここでは、サブシーケンスは連続している必要はありません。

例:

输入:[10, 9, 2, 5, 3, 7, 101, 18]
输出:4
解释:最长的上升子序列是[2, 3, 7, 101],长度为4

説明:

  • 最長の昇順サブシーケンスには複数の組み合わせがある場合があり、対応する長さを出力するだけで済みます。
  • アルゴリズムの時間計算量はO(n ^ 2)である必要があります

上級:

  • アルゴリズムの時間計算量をO(nlgn)に減らすことができますか?

方法1:動的計画

アイデア:

意味を定義するにはdp最初の配列:サブインクリメントのシーケンスの最長の長さのdp[i]として表されます。nums[i]结尾

といった:

インデックス 0 1 2 3 4 5
nums 1 4 3 4 2 3
dp 1 2 2 3 2

アルゴリズムの進化プロセスは次のとおりです。

この定義によれば、最終結果(サブシーケンスの最大長)は、dp配列の最大値、つまり次のようになります。

int res = 0;
for(int i = 0; i < dp.length; i++){
    
    
  	res = Math.max(dp[i], res);
}
return res;

状態遷移方程式を見つけます。

以前のdp配列の定義によると、今はdp[5]を見つけたい、つまりnums[5] 为结尾、最長増加部分列を見つけたいと思っています

nums[5] = 3これは増加するサブシーケンスであるため、末尾が3未満の前のサブシーケンスを見つけてから、末尾に3を追加して新しい増加するサブシーケンスを形成するだけで、この新しいサブシーケンスの長さが1つ長くなります。

もちろん、多くの新しいサブシーケンスが形成される可能性がありますが、必要なのは最長のものだけであり、最長のサブシーケンスの長さをdp [5]の値として使用できます。

dp [5] = max {dp [0] + 1、nums [0] = 1 <nums [5] dp [4] + 1、nums [4] = 2 <nums [5] dp [5] = max \ begin {cases} dp [0] + 1、\ quad nums [0] = 1 <nums [5] \\ dp [4] + 1、\ quad nums [4] = 2 <nums [5] \ end {cases } d p [ 5 ]=m a x{{ d p [ 0 ]+1 n u m s [ 0 ]=1<n u m s [ 5 ]d p [ 4 ]+1 n u m s [ 4 ]=2<N U M S [ 5 ]

最終的な状態遷移方程式は次のとおりです。

dp [n] = max {dp [i] + 1、i∈[0、n − 1] andnums [i] <nums [n]} dp [n] = max \ {dp [i] + 1、\ quad i \ in [0、n-1] \ quadおよび\ quad nums [i] <nums [n] \} d p [ n ]=m a x { d p [ i ]+1 [ 0 n1 ]a n dn u m s [ i ]<n u m s [ n ] }

基本ケースは1であり、サブシーケンスには少なくともそれ自体が含まれている必要があるため、dp配列はすべて1に初期化する必要があります。したがって、最小の長さは1です。

import java.util.*;

class Solution {
    
    
    public int findNumberOfLIS(int[] nums) {
    
    
      	int[] dp = new int[nums.length];
      	Arrays.fill(dp, 1);
      	int res = 0;
      	for(int i = 0; i < nums.length; i++){
    
    
          	for(int j = 0; j < i; j++){
    
    
              	if(nums[j] < nums[i]){
    
    
                  	dp[i] = Math.max(dp[i], dp[j]+1);
                }
            }
          	res = Math.max(res, dp[i]);
        }
      	return res;
    }
}

時間計算量:O(n ^ 2)

スペースの複雑さ:O(n)

方法2:二分探索のアイデア

二分探索のアイデアについては、この記事を見ることができます動的計画法設計の最長増加部分列

class Solution {
    
    
    public int findNumberOfLIS(int[] nums) {
    
    
      	int[] top = new int[nums.length];
      	int piles = 0;
      	for(int i = 0; i < nums.length; i++){
    
    
          	int poker = nums[i];
          	int left = 0;
          	int right = piles;
          	while(left < right){
    
    
              	int mid = left + (right - left)/2;
              	if(top[mid] > poker){
    
    
                  	right = mid;
                }else if(top[mid] < poker){
    
    
                  	left = mid + 1;
                }else{
    
    
                  	right = mid;
                }
            }
          
          	if(left == piles) piles++;
          	top[left] = poker;
        }
      	return piles;
    }
}

時間計算量:O(nlgn)

スペースの複雑さ:O(n)

おすすめ

転載: blog.csdn.net/weixin_44471490/article/details/109030232