[leetcode] Longest Increasing Subsequence

Longest Increasing Subsequence

  • 問題描述:計算一個數組的最長上升子序列。這個子序列內的元素不一定要是相鄰的。比如說數組{1, 100, 2, 3, 4}的LIS就爲{1, 2, 3, 4}
  • 解法1-動態規劃
    • 首先我們將問題劃分成子問題=>我們該序列一定是以某一個點爲起點的。所有我們另dp[i]表示以i爲起點的LIS長度。
    • 構造父問題的解。假設說我們已經知道了dp[i],那麼我們如何構造dp[i-1]呢?注意,這裏我們構造的是dp[i-1],而不是dp[i+1].針對dp[i-1]的所能得到的所有結果就是,nums[i-1] < nums[j] 所有j點中的最大值+1或者就是本身的dp[i-1] 即忽略該點。
    • 總結下來dp[i] = max(dp[i], dp[j]+1) j[i+1,n)   and   nums[j]&gt;nums[i]j\in[i+1, n)\ \ \ and\ \ \ nums[j] &gt; nums[i]
    • 代碼:
int lengthOfLISV2(vector<int>& nums) {
        int size = (int) nums.size();
        if(size == 0)
            return 0;
        int dp[size]; // dp[i]表示以i開頭的位置
        memset(dp, 0, sizeof(dp));
        int res = 0;
        for(int i=size-1;i>=0;i--){
            for(int j=i+1;j<size;j++){
                if(nums[i] <= nums[j]){
                    dp[i] = max(dp[i], dp[j] + 1);
                    res = max(res, dp[i]);
                }
            }
        }
        return res + 1;
    }
  • 解法2:O(NlogN):
    • 參照1, 2
    • 我們新建一個數組B,保存可能是最後subsequence的數字。
    • 我們遍歷輸入數組A中的每個數組,針對該數字a,我們在B中找到小於它的最大數字
      • 如果B中所有數字都小於a,則我們直接將a加入B中,代表我們從開始的點,到當前數字a能生成的LIS長度一定會增加1。
      • 如果B中所有數字都大於a, 則我們B中的第一個數字置換成a,代表我們可能會從新開始一個新的subsequence。⚠️我們並沒有改變B的大小。所有最後的LIS的長度不會改變。
      • 如果a在B中間,我們將B中最大的小於a的元素替換成a。道理和上一種情況是一樣的。
    • 最後B的大小,就是我們所能返回LIS的長度。
    • 概括來說,當由SubArray[:i-1]構造SubArray[:i]的解時候,如果nums[i]在SubArray[:i-1]對應的Subsequence之間的話,則我們把其中最大的小於nums[i]的替換成nums[i]。因爲原來的數字已經沒有用了,它起的作用完全可以由nums[i]代替,所以我們可以將其替換掉。
    • 代碼
int lengthOfLISV3(vector<int>& nums) {
        vector<int> saved_num;
        for(auto n: nums){
            auto it = lower_bound(saved_num.begin(), saved_num.end(), n);
            if(it == saved_num.end()){
                saved_num.push_back(n);
            }else{
                *it = n;
            }
        }
        return saved_num.size();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章