LIS最长上升子序列O(nlogn)算法
Posted thesilvermoon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LIS最长上升子序列O(nlogn)算法相关的知识,希望对你有一定的参考价值。
正常的求LIS的方法是用dp来做,时间复杂度为O(n^2),但是面对一些题目的时候这个复杂度就有点高了,就去学了一下nlogn的解法。主要运用到了二分查找,stl里面的lower_bound 也可以。
upper_bound(i) 返回的是键值为i的元素可以插入的最后一个位置(上界)
lower_bound(i) 返回的是键值为i的元素可以插入的位置的第一个位置(下界)
先贴一发O(n^2)的代码
1 #include <bits/stdc++.h> 2 #define fi first 3 #define se second 4 #define pb push_back 5 #define fio ios::sync_with_stdio(false);cin.tie(0); 6 #define pii pair<int,int> 7 #define vi vector<int> 8 #define vc vector<char> 9 #define mii map<int,int> 10 #define si(a) scanf("%d",&a) 11 #define ss(a) scanf("%s",&a) 12 #define sl(a) scanf("%I64d",&a); 13 #define slf(a) scanf("%lf",&a); 14 #define CLEAR(a,b) memset(a,b,sizeof(a)) 15 #define pi acos(-1) 16 17 const int INF=0x3f3f3f3f; 18 const int N=2e5+5; 19 20 typedef long long ll; 21 typedef double db; 22 typedef unsigned long long ull; 23 using namespace std; 24 int dp[N]; 25 int num[N]; 26 int n; 27 28 void solve() 29 { 30 int res=0; 31 for (int i=0;i<n;i++) 32 { 33 dp[i]=1; 34 for (int j=0;j<i;j++) 35 { 36 if(num[j]<num[i]) 37 { 38 do[i]=max(dp[i],dp[j]+1); 39 } 40 res=max(res,dp[i]); 41 } 42 } 43 cout<<res<<endl; 44 } 45 int main() 46 { 47 fio; 48 int n; 49 cin>>n; 50 for (int i=0;i<n;i++) 51 { 52 cin>>num[i]; 53 } 54 solve(); 55 }
这个很好理解,对于O(nlogn)的解法我看了一些博客,里面比较重要的就是替换这个操作,每次找到一个比最后一个还要大的值的时候直接加入后面,碰到比最后面小的数字的时候往里面找第一个比它小的数字,替换掉后面一个。(语文不好。。。直接看例子吧)
如2 5 3 4 9 7 8 10 很容易就能看出来它的LIS长度为6,最长的是 2 3 4 7 8 10。
具体步骤如下,2进入;5比2大,进入;此时因为3比5小,往里找,2比3小,3替换掉5;4比3大,4进入;9比4大,9进入;7比9小,往前找,4比7小,7替换掉9;后面都直接进入,得到LIS序列2 3 4 7 8 10。
O(nlogn)的代码具体如下
1 #include <bits/stdc++.h> 2 #define fi first 3 #define se second 4 #define pb push_back 5 #define fio ios::sync_with_stdio(false);cin.tie(0); 6 #define pii pair<int,int> 7 #define vi vector<int> 8 #define vc vector<char> 9 #define mii map<int,int> 10 #define si(a) scanf("%d",&a) 11 #define ss(a) scanf("%s",&a) 12 #define sl(a) scanf("%I64d",&a); 13 #define slf(a) scanf("%lf",&a); 14 #define CLEAR(a,b) memset(a,b,sizeof(a)) 15 #define pi acos(-1) 16 17 const int INF=0x3f3f3f3f; 18 const int N=2e5+5; 19 20 typedef long long ll; 21 typedef double db; 22 typedef unsigned long long ull; 23 using namespace std; 24 int ans[N]; 25 int num[N]; 26 27 int main() 28 { 29 fio; 30 int n; 31 cin>>n; 32 for (int i=1;i<=n;i++) 33 cin>>num[i]; 34 ans[1]=num[1]; 35 int len=1; 36 for(int i=2;i<=n;i++) 37 { 38 if(num[i]>ans[len]) 39 ans[++len]=num[i]; 40 else 41 { 42 int pos=lower_bound(ans,ans+len,num[i])-ans; 43 ans[pos]=num[i]; 44 } 45 } 46 for (int i=1;i<=len;i++) 47 { 48 cout<<ans[i]<<" "; 49 } 50 cout<<endl; 51 } 52 53 54 /* 55 8 56 2 5 3 4 9 7 8 10 57 */
以上是关于LIS最长上升子序列O(nlogn)算法的主要内容,如果未能解决你的问题,请参考以下文章