300 Longest Increasing Subsequence

最长递增子序列
举个例子来说明算法:

[5,6,7,1,2,8]

用一个IS矩阵来递增子序列,IS[i]表示长度为i的递增子序列。我们来看在扫描整个数组的过程中这个矩阵如何变化。

at 5:
[[], [5]]

at 6:
[[], [5],  [5,6]]

at 7:
[[], [5],  [5,6], [5,6,7]]

at 1:
[[], [1],  [5,6], [5,6,7]]

at 2:
[[], [1],  [1,2], [5,6,7]]

at 8:
[[], [1],  [1,2], [5,6,7], [5,6,7,8]]

来一个新的数,我们就往前扫描找到它可以append的位置。例如扫描到2的时候,它可以append在[1]之后形成[1,2], 并且我们希望用[1,2]代替[5,6] 成为新的长度为2的sub sequence。

  • 注意:在往前扫描的时候,每个sub sequence的最后一个数是单调的,所以可以采用binary search的方法来找到这个新的数可以插入的位置。
  • 并且:每个新的数一定只有一个插入的位置。(想想为啥。)
  • 这样算法的复杂度就是$$NlogN$$。

Solution-1 利用排序+最长公共子序列的方法

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if ( n == 0 or n == 1) return n;
        vector<int> help(n, 0);
        for ( int i = 0; i <= n-1; i++) help[i] = nums[i];
        sort(help.begin(), help.begin()+n);
        vector<int> result(n, 0), tmp(n, 0);
        // 1st index help's; 2nd index nums;
        result[0] = (nums[0] == help[0]);
        for ( int i = 1; i <= n-1; i++ ) {
            if ( nums[i] == help[0] ) result[i] = 1;
            else result[i] = result[i-1];
        }
        for ( int i = 1; i <= n-1; i++ ) {
            result.swap(tmp);
            if ( help[i] == help[i-1] ) {
                result = tmp;
                continue;
            }
            if ( help[i] == nums[0] ) result[0] = 1;
            else result[0] = tmp[0];
            for ( int j = 1; j <= n-1; j++ ) {
                result[j] = max(tmp[j], result[j-1]);
                if ( help[i] == nums[j] ) result[j] = max(result[j], tmp[j-1] + 1);
            }
        }
        return result[n-1];
    }
};

Solution-2
use upper_bound()

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if ( n == 0 ) return 0;
        vector<vector<int>> res(1, vector<int>(1, nums[0]));
        vector<int> help(1, nums[0]);
        for ( int i = 1; i <= n-1; i++ ) {
            int nres = res.size();
            int pos = upper_bound(help.begin(), help.end(), nums[i]) - help.begin();
            if ( pos == 0 ) {
                res[0][0] = nums[i];
                help[0] = nums[i];
                continue;
            }
            if ( res[pos-1][pos-1] == nums[i] ) continue;
            if ( pos == nres ) {
                vector<int> tmp = res[nres-1];
                tmp.push_back(nums[i]);
                res.push_back(tmp);
                help.push_back(nums[i]);
                continue;
            }
            vector<int> tmp = res[pos-1];
            tmp.push_back(nums[i]);
            res[pos] = tmp;
            help[pos] = nums[i];
        }
        return res.size();
    }
};

a simplified solution

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if ( n <= 1 ) return n;
        vector<int> res(1, nums[0]);
        for ( int i = 1; i <= n-1; i++ ) {
            int nres = res.size();
            if ( nums[i] > res[nres-1] ) {res.push_back(nums[i]); continue;}
            // firnd the first element in res ( res[j] ) s.t. res[j] > nums[i]
            for ( int j = 0; j <= nres-1; j++) {
                if ( j == 0 and nums[i] < res[j] ) {
                    res[j] = nums[i];
                    break;
                }
                if ( nums[i] < res[j] and nums[i] != res[j-1] ) {
                    res[j] = nums[i];
                    break;
                }
            }
        }
        return int(res.size());
    }
};

Converted to binary-search solution

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if ( n <= 1 ) return n;
        vector<int> res(1, nums[0]);
        for ( int i = 1; i <= n-1; i++ ) {
            int nres = res.size();
            if ( nums[i] > res[nres-1] ) {res.push_back(nums[i]); continue;}
            if ( nums[i] < res[0] ) {res[0] = nums[i]; continue;}
            if ( nums[i] == res[0] or nums[i] == res[nres-1] ) continue;
            int l = 0, r = nres-1, m; 
            // firnd the first element in res ( res[j] ) s.t. res[j] > nums[i]
            while ( true ) {
                if ( l+1 == r ) { res[r] = nums[i]; break;}
                m = (l+r)/2;
                if ( nums[i] == res[m] ) break;
                if ( nums[i] < res[m] ) r = m;
                else l = m;
            }
        }
        return int(res.size());
    }
};

results matching ""

    No results matching ""