[LeetCode] 673. Number of Longest Increasing Subsequence 最長遞增序列的個數


 

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/

https://leetcode.com/problems/number-of-longest-increasing-subsequence/discuss/107318/C%2B%2B-DP-with-explanation-O(n2)

https://leetcode.com/problems/number-of-longest-increasing-subsequence/discuss/107293/JavaC%2B%2B-Simple-dp-solution-with-explanation

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM