300. 最長上升子序列(動態規劃)
阿新 • • 發佈:2020-07-19
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]
✓ 以 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[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] 後面,跳過此次遍歷(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