lis最長上升子序列o(nlogn)優化

<font size=4> ## LIS的暴力算法 咱們知道,LIS(最長上升子序列,最長降低子序列,最長不上升子序列,最長不降低子序列)若是按照最初得方法作,咱們設置的狀態f[i]表示i結尾的最長LIS的長度,在枚舉每個數的時候都要向前找一個數字,那麼這種方法是O(n^2).([具體講解看這裏](https://blog.csdn.net/ronaldo7_zyb/article/details/81052793))ios


優化後的LIS

若是N≤700000呢?O(n^2)的算法顯然是不符合要求的,咱們能夠考慮優化LIS的DP 咱們以最長上升子序列爲例: 咱們設f[i]爲長度爲i的最長上升子序列結尾的最小個數. 那麼,咱們在枚舉新的數字a[i]的時候,若是a[i]要比枚舉的f[j]大,則說明以a[i]結尾必然可以造成長度爲j+1的最長上升子序列.咱們能夠選擇來模擬這個過程. 設這串序列爲{2,1,6,5,8,0,1,5,10} 1.由於沒有數字,f[]={2} 2.由於1比2小,1沒法接在任何數字後面,因此替代2,f[]={1} 3.由於6比任何一個數都要大,因此接在最前面,f[]={1,6} 4.5能夠接在1後面而且比6要小,以此代替6,f[]={1,5} 5.由於8比任何數要大,接在末尾,f[]={1,5,8} 6.0比任何數都要小,因此f[]={0,5,8} 7.1能夠接在0後面,因此f[]={0,1,8} 8.5能夠接在8後面,因此f[]={0,1,5} 9.10能夠接在5後面,因此f[]={0,1,5,10} 由於f[4]不爲0,說明能夠構成長度爲4的最長上升子序列,故答案爲4 爲何咱們要在新的數字要是f[]數組內的原有值最小?由於這樣更可讓後面的數字構成最長上升組序列.所以咱們須要在這個序列中查找,找到一個位置使得前面的數比它小而且後面的數字大於等於它,使得它可以覆蓋這個數字.那麼,這個算法的時間複雜度仍而後O(n^2),顯然沒法優化. 不難發現,這個序列是單調遞增的,那麼咱們即可以選擇在查找的時候去優化,在單調遞增的序列中咱們能夠需用二分查找去尋找那個能夠覆蓋的位置,而二分查找的時間複雜度是O(lgn),再加上枚舉1-n的時間複雜度,故總複雜度爲:O(n)*O(logn)=O(nlogn),顯然能夠作到. 再從新說一下大體思路: 1.枚舉a[1...n]這些數字 2.若是這個數組比f數組末尾的數子要大,說明不能覆蓋任何一個數字,則放在最後 3.不然,用二分查找進行查詢位置並進行覆蓋. 同理,另外3中LIS也能夠實現. 有一個須要注意的地方,那就是:若是作上升的和不降低的LISf[0]須要賦值爲-∞,不然賦值爲+∞,我在這裏用pow(10,9)(即10的9次方的意思)在進行f[0]的初始化.由於可能會出現負數c++


LIS模板題

有N個整數,輸出這N個整數的最長上升序列、最長降低序列、最長不上升序列和最長不降低序列。 根據上述分析,咱們應該十分容易就可以寫出最後的程序,四個序列的代碼基本類似 代碼以下:算法

#include<bits/stdc++.h>
using namespace std;
int n;
int a[800000];
int f[800000];
void Lis1()
{
    
	memset(f,0,sizeof(f));
	int len=0,pos;f[0]=-pow(10,9);
	for (int i=1;i<=n;i++)
	{
		if (a[i]>f[len]) f[++len]=a[i];
		else
		{
			int L=1,R=len,Mid;
			while (L+1<R)
			{
				Mid=(L+R)>>1;
				if (a[i]>f[Mid]) L=Mid;
				else R=Mid;
			}
			if (a[i]>f[L]) pos=R;
			else pos=L;
			f[pos]=min(f[pos],a[i]); 
	    }
	}
	cout<<len<<endl;
}
void Lis2()
{
	memset(f,0,sizeof(f));
	int len=0,pos;f[0]=pow(10,9);
	for (int i=1;i<=n;i++)
	{
		if (a[i]<f[len]) f[++len]=a[i];
		else
		{
			int L=1,R=len,Mid;
			while (L+1<R)
			{
				Mid=(L+R)>>1;
				if (a[i]<f[Mid]) L=Mid;
				else R=Mid;
			}
			if (a[i]<f[L]) pos=R;
			else pos=L;
			f[pos]=max(f[pos],a[i]);
		}	
	}
	cout<<len<<endl;
}
void Lis3()
{
	memset(f,0,sizeof(f));
	int len=0,pos;f[0]=pow(10,9);
	for (int i=1;i<=n;i++)
	{
		if (a[i]<=f[len]) f[++len]=a[i];
		else
		{
			int L=1,R=len,Mid;
			while (L+1<R)
			{
				Mid=(L+R)>>1;
				if (a[i]<=f[Mid]) L=Mid;
				else R=Mid;
			}
			if (a[i]<=f[L]) pos=R;
			else pos=L;
			f[pos]=max(f[pos],a[i]); 
		}
	}
	cout<<len<<endl;
}
void Lis4()
{
	memset(f,0,sizeof(f));
	int len=0,pos;f[0]=-pow(10,9);
	for (int i=1;i<=n;i++)
	{
		if (a[i]>=f[len]) f[++len]=a[i];
		else
		{
			int L=1,R=len,Mid;
			while (L+1<R)
			{
				Mid=(L+R)>>1;
				if (a[i]>=f[Mid]) L=Mid;
				else R=Mid;
			}
			if (a[i]>=f[L]) pos=R;
			else pos=L;
			f[pos]=min(f[pos],a[i]); 
		}	
	}
	cout<<len<<endl;
}
int main()
{
	ios::sync_with_stdio(false);
	cin>>n;
	for (int i=1;i<=n;i++)

		cin>>a[i];
	Lis1();
	Lis2();
	Lis3();
	Lis4();
	return 0;
}
相關文章
相關標籤/搜索