Leetcode 300. Longest Increasing Subsequences (nlogn複雜度)思路解析

題目

Given an unsorted array of integers, find the length of longest increasing subsequence.

For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.

Your algorithm should run in O(n2) complexity.

Follow up: Could you improve it to O(n log n) time complexity?

Credits:
Special thanks to @pbrother for adding this problem and creating all test cases.

思路解析

維護一份最大長度遞增子序列對應的末尾元素爲最小的狀態數組,dp[len] = min(所有長度爲len的子序列第len個元素)

暴力法: 2層循環,最外層每次迭代時,當前元素挨個與子序列比較,如果當前值與之前的dp數組對應的子序列構成了更長的序列,則更新。遍歷的次數是(n-1)*n/2,時間複雜度爲O(n^2)。

最優解:其實dp數組是單調遞增,所以可以把內存循環的比較過程改成二分查找的方式,二分的時間複雜度爲O(logn),所以優化後的時間複雜度是O(nlogn)

C++實現

暴力解:時間複雜度O(n^2), Runtime: 39 ms

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if (0 == nums.size()) return 0;
        int global_max = 0;
        vector<int> ret(nums.size());
        for (int i = 0; i < nums.size(); ++i) {
            ret[i] = 1;
            for (int j = 0; j < i; ++j) {
                if (nums[i] > nums[j]) {
                    ret[i] = max(ret[i], ret[j]+1);
                }
            }
            global_max = max(ret[i], global_max);
        }
        return global_max;
    }
};

最優解:時間複雜度O(nlogn), Runtime: 3 ms

class Solution {

// 找到第一個大於target的下標
private:
    int binaryFind(vector<int> dp, int target) {
        if (0 == dp.size()) return 0;
        int low = 0;
        int high = dp.size() - 1;
        if (dp[high] < target) return dp.size();
        while (low <= high) {
            int mid = (low+high)/2;
            // 注意這裏需要等號,否則對於相同的連續值會算成多個,比如[2,2]會被誤判成長度爲2的遞增子序列
            if (dp[mid] >= target) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return low;
    }

public:
    int lengthOfLIS(vector<int>& nums) {
        if (0 == nums.size()) return 0;
        vector<int> dp;
        for (int i = 0; i < nums.size(); ++i) {
            int idx = binaryFind(dp, nums[i]);
            if (idx == dp.size()) dp.push_back(nums[i]);
            else dp[idx] = nums[i];
        }
        return dp.size();
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章