題目:
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.
題解:
首先解決最長的遞增序列問題,最朴素的做法是深搜,以每一個數為開頭,找位置在它后面的且數值比它大的為下一層,顯然會超時,考慮用動態規划去解決問題(也就是最長上升序列(LIS),一個經典的動態規划問題)。其實就是LIS的變體。 摘自九章算法
1. 設dp[i]為以該數結尾,能構成的最長序列的長度。進行連接的時候,對於每個數字num[i],遍歷位置在它之前的數字num[j],如果比這個數小(num[j]<num[i]),也就是能構成一個序列,這樣就能進行狀態轉移,我們令dp[i]=max(dp[i],dp[j]+1)來保證存儲的為最長長度,同時可以記錄max(dp[i])
2. 考慮完題目的長度優先后,我們考慮數量,也就是說最長長度的序列有幾個,這個問題需要我們在處理dp的時候來記錄,我們設ans[i]為以第i個數結尾的最長序列的個數,與dp同理,ans初值也都是1
3. 狀態轉移的時候,如果dp更新了,也就是說(dp[j]+1>dp[i])說明這個長度的序列是新出現的,我們需要將ans[i]設置為ans[j],因為新序列中,最新的數提供了序列的尾巴,數量是由前面積累的(或者說轉移);舉例序列[1 1 3 7]我們易得數字3對應的dp=2,ans=2,因為可以構成兩個[1 3]那么我們操作到數字7的時候,發現接在3后面最長,就可以轉移ans來作為初始數量
4. 而當dp[j]+1==dp[i]的時候,如同樣例,操作7的時候,我們最先發現了可以接在5后面,最長序列[1 3 5 7],然后發現可以接在4后面,[1 3 4 7],長度也是4,這時候就同樣需要轉移ans,加上去 ans[i]+=ans[j]
5. 最后我們需要遍歷dp,找到dp[i]=我們記錄的最大值的時候,累加我們得到的ans[i],即為所求結果,時間復雜度是O(n^2)
Solution
class Solution { public: int findNumberOfLIS(vector<int>& nums) { int n = nums.size(), max_len = 1, res = 0; vector<int> dp(n, 1), cnt(n, 1); for(int i = 1; i < n; ++i){ for(int j = 0; j < i; ++j){ if(nums[j] < nums[i] && dp[j] + 1 > dp[i]){ dp[i] = dp[j] + 1; cnt[i] = cnt[j]; } else if(nums[j] < nums[i] && dp[j] + 1 == dp[i]){ cnt[i] += cnt[j]; } } max_len = max(max_len, dp[i]); } for(int i = 0; i < n; ++i) if(dp[i] == max_len) res += cnt[i]; return res; } };