1. 程式人生 > 實用技巧 >[LeetCode] 300. Longest Increasing Subsequence 最長遞增子序列

[LeetCode] 300. Longest Increasing Subsequence 最長遞增子序列

動態規劃的核心設計思想是數學歸納法。

數學歸納法思想:

  比如我們想證明一個數學結論,那麼我們先假設這個結論在k<n時成立,然後根據這個假設,

想辦法推導證明出k=n的時候此結論也成立。如果能夠證明出來,那麼就說明這個結論對於k等於

任何數都成立。

設計動態規劃演算法:

  找到了問題的「狀態」,使用一個dp陣列描述、儲存問題的狀態。假設dp[0...i-1]都已經被算

出來了,然後問自己:怎麼通過這些結果算出dp[i]

對於本題,求最長遞增子序列,

1. 定義狀態:定義dp[i]表示以nums[i]這個數結尾的最長遞增子序列的長度。

2.處理 base case:dp[i]初始值為 1,因為以nums[i]

結尾的最長遞增子序列起碼要包含它自己。

3.分析狀態轉移:假設 dp[0...i-1] 都已經被算出來了,然後問自己:怎麼通過這些結果算出 dp[i]?

dp[i] = dp[k]+1; dp[k]滿足以下條件:0=<k<i, nums[k]<nums[i], dp[k]是dp[o:i-1]中的最大值。若

沒有滿足條件的dp[k],則dp[i] = 1 。具體參考程式碼中的處理。

按照以上思路,程式碼實現如下:

 1 class Solution {
 2 public:
 3     //dp O(n^2)
 4     int lengthOfLIS(vector<int
>& nums) 5 { 6 if(nums.empty()) 7 { 8 return 0; 9 } 10 const int nums_len = nums.size(); 11 //base case 12 vector<int> dp(nums_len,1); 13 int res = 1; 14 for(int i = 1;i<nums_len;++i) 15 { 16 for
(int j = 0;j<i;++j) 17 { 18 if(nums[i]>nums[j]) 19 { 20 dp[i] = max(dp[i],dp[j]+1); 21 } 22 } 23 res = max(res,dp[i]); 24 } 25 return res; 26 } 27 28 };

至此,這道題就解決了,時間複雜度 O(N^2)。總結一下如何找到動態規劃的狀態轉移關係:

1、明確dp陣列所存資料的含義。這一步對於任何動態規劃問題都很重要,如果不得當

或者不夠清晰,會阻礙之後的步驟。

2、根據dp陣列的定義,運用數學歸納法的思想,假設dp[0...i-1]都已知,想辦法求出dp[i]

一旦這一步完成,整個題目基本就解決了。

但如果無法完成這一步,很可能就是dp陣列的定義不夠恰當,需要重新定義dp陣列的含義;或者

可能是dp陣列儲存的資訊還不夠,不足以推出下一步的答案,需要把dp陣列擴大成二維陣列甚至三維陣列。