最长上升子序列更快做法

在这里插入图片描述
如果采用O(N^2)的做法,时间复杂度将不能满足要求。N = 100000,因此至少得是nlogn级别的算法才可以。在上一种解法的基础上可以有更快的做法。我们可以利用单调队列类似的思想,剔除一些不需要加入的数, 比如队列里面只有3,然后第二个数是1, 这个时候由于1是小于3的,并且如果将3替换掉的话,后续更容易加数进去。如果先前的f[j] 和 后来的f[i]大小是一样的,那么 由于子序列的长度长度是一样,并且 后一个的最后一个元素a[i - 1]是小于前一个的最后一个元素a[i]的,如果不满足条件的话,那么f[i] = f[i -1] + 1 了,因为a[i] > a[i - 1]
在这里插入图片描述
对每一个子串的长度的大小是递增的并且随着上升子序列的长度变化,其末尾的元素是递增的。上图表示的是不同上升子序列的最小值的大小,可以看到是递增的。对于每一个数,我们要要找出小于这个数a[i]的最大的数。

代码:

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 100010;
int a[N], q[N]; //a保存输入数组, q保存的是i长度的最小末尾数
int n;

int main(){
    
    
    cin >> n;
    for(int i = 0; i < n ;i++){
    
    
        cin >> a[i];
    }
    
    q[0] = 2e9;
    int len = 0;
    for(int i = 0; i < n ;i++)
    {
    
    
        int l = 0, r = len;
        while(l < r)
        {
    
    
            int mid = l + r + 1 >> 1;
            if(q[mid] < a[i])  l = mid;
            else r = mid - 1;
        }
        q[r + 1] = a[i];
        len = max(len, r + 1);
    }
    cout << len << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44879626/article/details/108133744
今日推荐