【リコウ】300. 最長増加部分列<動的計画法>

[リコウ] 300. 最長の増加部分列

整数配列 nums を指定して、その中で厳密に増加する最長のサブシーケンスの長さを見つけます。
サブシーケンスは、残りの要素の順序を変更せずに配列から要素を削除する (または削除しない) ことによって配列から導出されるシーケンスです。たとえば、[3,6,2,7] は配列 [0,3,1,6,2,2,7] のサブシーケンスです。

例 1:
入力: nums = [10,9,2,5,3,7,101,18]
出力: 4
説明: 最も長く増加するサブシーケンスは [2,3,7,101] であるため、長さは 4 です。

例 2:
入力: nums = [0,1,0,3,2,3]
出力: 4

例 3:
入力: nums = [7,7,7,7,7,7,7]
出力: 1

ヒント:
1 <= nums.length <= 2500
- 1 0 4 10^41 04 <= nums[i] <=1 0 4 10^41 04

答え

5 つのステップをたどります。

  • dp 配列と添字の意味を決定します。これは、次のことを
    dp[j]意味します:i番目の数値で終わる最長の昇順サブシーケンスの長さ。選択する必要があることに注意してくださいnums[i]

  • 漸化式を決定する
    dp[i] を計算する前に、dp[0...i−1] の値が計算されているため、状態遷移方程式は次のようになります。


  • dp配列dp[0]=1を初期化する方法

  • 走査の順序を決定します。
    通常の走査は左から右です。

  • dp 配列を推測する例を考えてみましょう。
    入力は: 10 9 2 5 3 7 101、出力は:1 1 1 2 2 3 4
    入力は: 5 7 1 9 4 6 2 8 3、出力は:1 2 1 3 2 3 2 4 3

class Solution {
    
    
    public int lengthOfLIS(int[] nums) {
    
    
        if (nums.length == 0) {
    
    
            return 0;
        }
        
        int[] dp = new int[nums.length];
        dp[0] = 1;
        int maxans = 1;
        
        for (int i = 1; i < nums.length; i++) {
    
    
        	// 默认以i为结尾的最长串是1,只有它本身
            dp[i] = 1;
            // 从0 判断到 i
            for (int j = 0; j < i; j++) {
    
    
                if (nums[i] > nums[j]) {
    
    
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            // 取dp数组中的最大值
            maxans = Math.max(maxans, dp[i]);
        }
        return maxans;
    }
}

状態 dp[i] を計算する場合、dp[0…i−1] のすべての状態を通過するには O(n) 時間がかかるため、合計の時間計算量は O( n 2 n^ 2n2 )

おすすめ

転載: blog.csdn.net/qq_44033208/article/details/133169961