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]; } }