1. 程式人生 > 實用技巧 >300. 最長上升子序列(動態規劃)

300. 最長上升子序列(動態規劃)

https://leetcode-cn.com/problems/longest-increasing-subsequence/

1、題目:

  給定一個無序的整數陣列,找到其中最長上升子序列的長度。

示例:

輸入: [10,9,2,5,3,7,101,18]
輸出: 4
解釋: 最長的上升子序列是[2,3,7,101],它的長度是 4。
說明:

可能會有多種最長上升子序列的組合,你只需要輸出對應的長度即可。
你演算法的時間複雜度應該為O(n2) 。
進階: 你能將演算法的時間複雜度降低到O(n log n) 嗎?

2、思路:

(1)定義狀態:

◼ 假設陣列是 nums, [10, 2, 2, 5, 1, 7, 101, 18]

dp(i) 是以 nums[i] 結尾的最長上升子序列的長度,i ∈ [0, nums.length)
✓ 以 nums[0] 10 結尾的最長上升子序列是 10,所以 dp(0) = 1
✓ 以 nums[1] 2 結尾的最長上升子序列是 2,所以 dp(1) = 1
✓ 以 nums[2] 2 結尾的最長上升子序列是 2,所以 dp(2) = 1
✓ 以 nums[3] 5 結尾的最長上升子序列是 2、5,所以 dp(3) = dp(1) + 1 = dp(2) + 1 = 2
✓ 以 nums[4] 1 結尾的最長上升子序列是 1,所以 dp(4) = 1
✓ 以 nums[5] 7 結尾的最長上升子序列是 2、5、7,所以 dp(5) = dp(3) + 1 = 3
✓ 以 nums[6] 101 結尾的最長上升子序列是 2、5、7、101,所以 dp(6) = dp(5) + 1 = 4
✓ 以 nums[7] 18 結尾的最長上升子序列是 2、5、7、18,所以 dp(7) = dp(5) + 1 = 4

◼ 最長上升子序列的長度是所有 dp(i) 中的最大值 max { dp(i) },i ∈ [0, nums.length)

◼ 遍歷 j ∈ [0, i)
當 nums[i] > nums[j]
✓ nums[i] 可以接在 nums[j] 後面,形成一個比 dp(j) 更長的上升子序列,長度為 dp(j) + 1
✓ dp(i) = max { dp(i), dp(j) + 1 }

當 nums[i] ≤ nums[j]
✓ nums[i] 不能接在 nums[j] 後面,跳過此次遍歷(continue)


◼ 狀態的初始值
dp(0) = 1
所有的 dp(i) 預設都初始化為 1

3、程式碼

class Solution {
    public int lengthOfLIS(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int[] dp = new int[nums.length];
        int max = dp[0] = 1;
        for (int i = 1; i < nums.length; i++) {
            dp[i] = 1;
            //需要遍歷之前所有元素進行比較
            for (int j = 0; j < i; j++) {
                //若nums[i]<nums[i-1],沒法拼接,只要大於的
                if (nums[i] <= nums[j]) continue;
                dp[i] = Math.max(dp[i], dp[j] + 1);

            }
            max = Math.max(dp[i], max);
        }
        return max;
    }
}

還可以進一步優化,見ppt