スリー・ソリューションズ(LIS)最長増加部分列

スリー・ソリューションズ(LIS)最長増加部分列

1. LCS(LISシーク)時間Oの複雑さ(N ^ 2)

思考:オリジナルのシーケンスが新しいソートにシーケンスbを生成する後、最長共通部分列の結果LISを比較し、B。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int dp[2][N];//滚动数组优化 
string a,b;
int LCS(){	
	int la=a.size(),lb=b.size();
	for(int i=1;i<=la;i++)
		for(int j=1;j<=lb;j++)
			if(a[i-1]==b[j-1])//如果相等直接加1 
				dp[i%2][j]=dp[(i-1)%2][j-1]+1;
			else dp[i%2][j]=max(dp[i%2][j-1],dp[(i-1)%2][j]);//否则比较一下 
	return dp[la%2][lb]; 
}
int main(){
	cin>>a;
	b=a;
	sort(b.begin(),b.end());//b为排好序递增序列 
	cout<<LCS()<<endl;
	return 0; 
}

2.DP(時間Oの複雑さ(N ^ 2)

思考:セットDP [I]は、[I]である最長シーケンスの最後にインクリメントされ、最大値は1からI-1にそれぞれトラバースIJ見つかり。
即ちDP [I] = MAX(DP [J]、0)+1。 詳細については、コードを参照してください。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int dp[N],a[N],ans=1,n;//dp[i]表示以第i个数结尾的LIS的长度 
int lis(){  //时间复杂度O(n^2) 
	dp[1]=1;//初始化 
	for(int i=2;i<=n;i++)
	{
		int mx=0;//每次都为0 
		for(int j=1;j<i;j++)
			if(a[j]>a[i]&&dp[j]>mx)//如果a[j]>a[i]且dp[j]>mx 更新mx 
				mx=dp[j];
			dp[i]=mx+1;//更新dp[i] 
		ans=max(ans,dp[i]);//得到ans 
	}
	return ans;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	cout<<lis()<<endl;
	return 0;
}

3.補助アレイシミュレーションOの時間複雑度(nlogn)

アイデア:LISは補助配列で、各番号を保存します。番号は直接添加の終わりよりも大きい場合、2:最初の配列は、その置換より数の大きいを見つけるために、補助アレイの数は、両方の操作に使用されます。詳細については、コードを参照してください。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5; 
int a[N],d[N],n; //d[i]保存LIS的数字 
int  LIS(){
	int l=1;// l表示d[i]的长度 
	d[1]=a[1];//初始化 
	for(int i=2;i<=n;i++)
	{
		if(a[i]>d[l]) //如果大于d[l] 直接添加的末尾 
			d[++l]=a[i];
		else { //否则查找第一个大于a[i]的数 替换掉 
			int p=lower_bound(d+1,d+l+1,a[i])-d; //该数位置  复杂度 logn 
			d[p]=a[i];
		}
	}
	return l;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	cout<<LIS()<<endl;
	return 0;
}

演習。

1.ミサイルインターセプタ

タイトルは、ポータル、この問題は、C ++ STL検索機能要求はタイトル裸の複雑さO(nlogn)をLISの使用であり、
詳細なコードとして。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N],d1[N],d2[N],l1,l2,k;//d2[i]保存 最长不增子序列  d1[i]保存 LIS(严格递增) 
void fun(){
	l1=l2=1;
	d1[1]=d2[1]=a[1];
	for(int i=2;i<k;i++)
	{
		if(a[i]>d1[l1]) //这里必须是大于,不然两个数可以合并为一个拦截系统。 
			d1[++l1]=a[i];
		else {
			 int p=lower_bound(d1+1,d1+l1+1,a[i])-d1;
			 d1[p]=a[i];
		}
		if(a[i]<=d2[l2])
			d2[++l2]=a[i];
		else {   //因为查找第一个‘小于’ 而不是小于等于  所以要用upper_bound 
			 int p=upper_bound(d2+1,d2+l2+1,a[i],greater<int>())-d2; //从左到右找到第一个小于a[i]的数. 
			 d2[p]=a[i];
		}
	}
}
int main(){
	k=1;
	while(cin>>a[k]) k++; //这里不能debug了只能到文件结束才会有输出 
	fun();
	printf("%d %d\n",l2,l1);
	return 0;
}
公開された18元の記事 ウォン称賛14 ビュー353

おすすめ

転載: blog.csdn.net/weixin_45750972/article/details/105074724