nlogn求解最长上升子序列

nlogn求解最长上升子序列

先讲解两个函数 lower_bound()和upper_bound()

使用规范为

lower_bound(数组名+k,数组名+k+n,x,cmp)代表在数组[k]到数组[k+n]中查找x  并可以使用重载重新定义cmp  

upper_bound(数组名+k,数组名+k+n,x,cmp)代表在数组[k]到数组[k+n]中查找x  并可以使用重载重新定义cmp

两者的区别在于lower_bound()返回的是非降序列的第一个>=key的地址(指针

而upper_bound()返回的是非降序列的第一个>key的地址(指针

1.n方时间复杂度的最长上升子序列

int maxx=0;
for
(int i=1;i<=n;i++)//遍历整个数组的数字 {
   dp[i]=1;
for(int j=1;j<i;j++)//寻找当前最长的上升子序列长度 { if(num[i]>num[j]) dp[i]=max(dp[i],dp[j]+1);//状态转移方程 dp[i]=max(dp[i],dp[j]+1),代表在第i个数时最长上升子序列的长度 如果有更优解就更新dp数组 }
   maxx=max(dp[i],maxx);//维护一个最大值 }

 2.nlogn时间复杂度求解最长上升子序列

int len=1;
num[1]=dp[1];
for(int i=2;i<=n;i++)//遍历整个数组 寻找上升的序列
{
    if(dp[i]>num[len]){//如果符合条件 将其放入序列末端  
        num[++len]=dp[i];
    }
    else{//如果不符合条件 通过二分 寻找最后一个小于等于这个数的位置 并替换  因为是替换 所以不会影响总序列长度 
        int p=lower_bound(num+1,num+len+1,dp[i])-num;
        num[p]=dp[i];
    }
}

这样优化过后  时间复杂度缩减到 n*logn  既外层循环n 内层logn的时间复杂度

3.nlogn时间复杂度最长不上升子序列

struct cmp{
    bool operator()(int a,int b){return a>b;}
};



for(int i=2;i<=z;i++){
        if(dp1[len1]>=num[i])
            dp1[++len1]=num[i];
        else{
            int p1=upper_bound(dp1+1,dp1+1+len1,num[i],cmp())-dp1;
            dp1[p1]=num[i];
        }
}
人十我百 人百我万
原文地址:https://www.cnblogs.com/bestcoder-Yurnero/p/10685932.html