LIS总结(O(n^2), O(nlogn))

最长上升子序列(Longest Increasing Subsequence,LIS),在计算机科学上是指一个序列中最长的单调递增的子序列。

O(n^2)复杂度:

最长上升子序列(最长不下降子序列):

两者严格的区别是前者是严格递增的,后者允许有相同的值存在。

for(int i = 1;i <= n;i ++)
    {
        dp[i] = 1;
        for(int j = 1;j < i;j ++)
        {
            if(a[i] > a[j]) //此处如果改为 a[i] >= a[j]  那么求的则是最长不下降子序列
                dp[i] = max(dp[i], dp[j] + 1);
        }
        //ans = max(ans,dp[i]);
    }
    //cout << ans << endl;

最长下降子序列(最长不上升子序列):

for(int i = 1;i <= n;i ++)
    {
        dp[i] = 1;
        for(int j = 1;j < i;j ++)
        {
            if(a[i] < a[j]) //此处如果改为 a[i] <= a[j]  那么求的则是最长不下降子序列
                dp[i] = max(dp[i], dp[j] + 1);
        }
        ans = max(ans,dp[i]);
    }
    cout << ans << endl;

O(nlogn)复杂度:

运用 二分+贪心 实现

我们需要新建一个数组b  初始化都为inf  即很大的数,二分去找大于等于它的数 ,然后替换它 ,最后数出来有多少个数字不是

inf,就是长度,同时还能记录路径,一举两得

最长不下降子序列:

int b[n];
    memset(b,inf,sizeof(b));
    for(int i = 1;i <= n;i ++)
    {
        int pos = lower_bound(b + 1,b + n + 1, a[i]) - b;
        b[pos] = a[i];
    }
    int ans = 0;
    for(int i = 1;i <= n;i ++)
        if(b[i] != inf) ans ++;
    cout << ans << endl;

最长上升子序列只需要把里面的lower_bound 改为 upper_bound即可

最长下降子序列:

原理与上述类似  将a数组翻转,再求  

注意:最长下降子序列是在原数组a翻转过后用lower_bound,而最长不上升子序列则是用upper_bound  这点需要特别留心

int b[n];
    memset(b,inf,sizeof(b));
    reverse(a + 1,a + n +1);
    for(int i = 1;i <= n;i ++)
    {
        int pos = lower_bound(b + 1,b + n + 1, a[i]) - b;
        b[pos] = a[i];
    }
    int ans = 0;
    for(int i = 1;i <= n;i ++)
        if(b[i] != inf) ans ++;
    cout << ans << endl;

猜你喜欢

转载自blog.csdn.net/soul_97/article/details/81282710