Given an unsorted array of integers, find the number of longest increasing subsequence.
Example 1:
Input: [1,3,5,4,7] Output: 2 Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7].
Example 2:
Input: [2,2,2,2,2] Output: 5 Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.
Note: Length of the given array will be not exceed 2000 and the answer is guaranteed to be fit in 32-bit signed int.
這道題給了我們一個數組,讓求最長遞增序列的個數,題目中的兩個例子也很好的說明了問題。那么對於這種求極值的問題,直覺告訴我們應該要使用動態規划 Dynamic Programming 來做。其實這道題在設計 DP 數組的時候有個坑,如果將 dp[i] 定義為到i位置的最長子序列的個數的話,則遞推公式不好找。但是如果將 dp[i] 定義為以 nums[i] 為結尾的遞推序列的個數的話,再配上這些遞推序列的長度,將會比較容易的發現遞推關系。這里用 len[i] 表示以 nums[i] 為結尾的遞推序列的長度,用 cnt[i] 表示以 nums[i] 為結尾的遞推序列的個數,初始化都賦值為1,只要有數字,那么至少都是1。然后遍歷數組,對於每個遍歷到的數字 nums[i],再遍歷其之前的所有數字 nums[j],當 nums[i] 小於等於 nums[j] 時,不做任何處理,因為不是遞增序列。反之,則判斷 len[i] 和 len[j] 的關系,如果 len[i] 等於 len[j] + 1,說明 nums[i] 這個數字可以加在以 nums[j] 結尾的遞增序列后面,並且以 nums[j] 結尾的遞增序列個數可以直接加到以 nums[i] 結尾的遞增序列個數上。如果 len[i] 小於 len[j] + 1,說明找到了一條長度更長的遞增序列,那么此時將 len[i] 更新為 len[j]+1,並且原本的遞增序列都不能用了,直接用 cnt[j] 來代替。在更新完 len[i] 和 cnt[i] 之后,要更新 mx 和結果 res,如果 mx 等於 len[i],則把 cnt[i] 加到結果 res 之上;如果 mx 小於 len[i],則更新 mx 為 len[i],更新結果 res 為 cnt[i],參見代碼如下:
解法一:
class Solution { public: int findNumberOfLIS(vector<int>& nums) { int res = 0, mx = 0, n = nums.size(); vector<int> len(n, 1), cnt(n, 1); for (int i = 0; i < n; ++i) { for (int j = 0; j < i; ++j) { if (nums[i] <= nums[j]) continue; if (len[i] == len[j] + 1) cnt[i] += cnt[j]; else if (len[i] < len[j] + 1) { len[i] = len[j] + 1; cnt[i] = cnt[j]; } } if (mx == len[i]) res += cnt[i]; else if (mx < len[i]) { mx = len[i]; res = cnt[i]; } } return res; } };
下面這種方法跟上面的解法基本一樣,就是把更新結果 res 放在了遍歷完數組之后,我們利用 mx 來找到所有的 cnt[i],累加到結果 res 上,參見代碼如下:
解法二:
class Solution { public: int findNumberOfLIS(vector<int>& nums) { int res = 0, mx = 0, n = nums.size(); vector<int> len(n, 1), cnt(n, 1); for (int i = 0; i < n; ++i) { for (int j = 0; j < i; ++j) { if (nums[i] <= nums[j]) continue; if (len[i] == len[j] + 1) cnt[i] += cnt[j]; else if (len[i] < len[j] + 1) { len[i] = len[j] + 1; cnt[i] = cnt[j]; } } mx = max(mx, len[i]); } for (int i = 0; i < n; ++i) { if (mx == len[i]) res += cnt[i]; } return res; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/673
類似題目:
Longest Increasing Subsequence
Longest Continuous Increasing Subsequence
參考資料:
https://leetcode.com/problems/number-of-longest-increasing-subsequence/