1. 程式人生 > >LeetCode 最長遞增子序列的O(nlogn)詳解

LeetCode 最長遞增子序列的O(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 yo
* 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.
*
*****************************************************************************

/
求最長遞增子序列,此題中沒有要求這個序列,因此:
只需要將將比前一個數大的壓入陣列,如果一個數比其陣列中最大的數小,則在陣列中二分查詢找到它該在的位置。

//如果只要求最長遞增子序列的長度
int lengthOfLIS(vector<int>& nums) {
    vector<int> v;
    for (int i = 0; i<nums.size(); i++) {
        if (v.size() == 0 || v.back()<nums[i])
            v.push_back(nums[i]);
        else
{ int low = 0, high = v.size() - 1; while (low <= high) { int mid = low + (high - low) / 2; if (v[mid]<nums[i]) low = mid + 1; else high = mid - 1; } v[low] = nums[i]; } } return v.size(); }

下面是求這個最長遞增子序列的序列,其中dp[i]為以i位置結尾的最長遞增子序列的個數。

#include <iostream>
#include <vector>
#include<string>
#include<algorithm>
using namespace std;
//求DP
vector<int> getLIS(vector<int> &num){
    vector<int> ivec; //help
    int length = num.size();
    vector<int> dp(length);
    dp[0] = 1;
    ivec.push_back(num[0]);
    for (int i = 1; i < length; ++i) {
        if (ivec.back() < num[i]) {
            ivec.push_back(num[i]);
            dp[i] = dp[i - 1] + 1;
        }
        else {
            int low = 0, high = ivec.size() - 1;
            while (low <= high) {
                int mid = (low + high) / 2;
                if (ivec[mid] < num[i]) 
                    low = mid + 1;
                else 
                    high = mid - 1;
            }
            ivec[low] = num[i];
            dp[i] = low + 1;
        }
    }
    return dp;
}
//求最長遞迴子序列
vector<int> subArray(vector<int> &nums,vector<int> &dp) {
    int len = 0, index = 0;
    for (int i = 0; i < dp.size(); i++) {
        if (dp[i] > len) {   //找到最長遞增子序列的最後一個值
            len = dp[i];
            index = i;
        }
    }
    vector<int> result(len);
    result[--len] = nums[index];
    for (int i = index; i >= 0; i--) {
        if (nums[i] < nums[index] && dp[i] == dp[index] - 1) {
            result[--len] = nums[i];
            index = i;
        }
    }
    return result;
}

int main() {
    vector<int> n = { 3,5,6,2,5,4,19,5,6,7,12 };
    vector<int>dp = getLIS(n);
    vector<int>result = subArray(n, dp);
    for (auto c : result)
        cout << c << endl;
}