刪除最少的元素 LIS

LIS複雜度爲O(nlogn)O(nlogn)的算法:

int ans[MAX_N],a[MAX_N],dp[MAX_N],n; //a是數組序列,ans 用來保存每個dp值對應的最小值 
int len; //LIS 最大值
ans[1] = a[1] ;
len =1;
for(int i=2;;i++){
	if(a[i]>ans[len]){
		ans[++len] = a[i];
	}
	else{
		int pos = lower_bound(ans+1,ans+len+1,a[i]) -ans;
		ans[pos] =a[i];
	}
} 
cout<<len<<endl; //len 就是LIS的值 

LIS:由貪心的思想,用dp[len]保存長度爲len的子序列中結尾最小的那個值。比如第i個位置的數爲x,它與那些1~i-1中的結尾小於x的子序列構成新的子序列。遍歷dp,找到第一個大於x的位置pos(知x>dp[pos1],x<dp[pos]x>dp[pos-1],x<dp[pos]),更新其值爲x,即對應長度的子序列結尾值被更新(變得更小)。
LIS的各種變體對應解決策略 O(n2)O(n^2)

  • 最長上升子序列 lower_bound()
  • 最長不上升子序列 dp數據乘以-1,upper_bound()
  • 最長下降子序列 dp數據乘以-1,lower_bound()
  • 最長不下降子序列 upper_bound()

STL二分搜索:
頭文件 #include< algorithm>
upper_bound(first,last,val):返回從first到last的左閉右開區間中第一個大於 val的位置。
lower_bound(first,last,val):返回從first到last的左閉右開區間中第一個大於等於 val的位置。

方法1

r[1]r[i]r[1]\sim r[i]複雜度爲O(n2)O(n^2),r[i]r[n]r[i]\sim r[n]複雜度爲O(nlogn)O(nlogn)

#include<iostream>
#include<stdio.h> 
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1010];
int r[1010];
int main(){
	//freopen("in.txt","r",stdin);
	int n;
	cin>>n;
	int index = 0;
	for(int i = 1;i<=n;i++){
		cin>>r[i];
	}
	int M = 0;
	int ans = 0;
	for (int i = 1;i<=n;i++){
		ans = 0;
		memset(dp,0,sizeof(dp)); 
		for(int p =1;p<=i;p++){ // 計算從 r[1]~ r[i] 的最長不上升子序列 
			dp[p] = 1;//  單個節點也可視爲長爲1的序列,初始化爲1  
			for(int q = 1;q<p;q++){
				if(r[p]<=r[q]){
					dp[p] = max(dp[p],dp[q]+1);
				}
			}
			ans = max(ans,dp[p]);
		}
		//cout<<i<<'\n';
		//cout<<ans<<'\n';
		int len = 1; // LIS 最大值 
		dp[i+len] =r[i];
		for(int p = i+1;p<=n;p++){ //計算 從 r[i]~ r[n]的最長不下降子序列 
			if(r[p]>=dp[i+len]){
				dp[++len+i] = r[p];
			}
			else{
				int pos = upper_bound(dp+i+1,dp+i+len+1,r[p])-dp;
				dp[pos] = r[p];
			}
		}
		//cout<<len<<"\n\n";
		if(len+ans-1>=M){
			M =len+ans-1;
		}
	}
	cout<<n-M<<"\n";
	return 0;
}

方法2

總體複雜度爲O(nlogn)O(nlogn)

#include<iostream>
#include<stdio.h> 
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1010];
int r[1010];
int main(){
	//freopen("in.txt","r",stdin);
	int n;
	cin>>n;
	int index = 0;
	for(int i = 1;i<=n;i++){
		cin>>r[i];
	}
	int M = 0;
	int ans = 0;
	for (int i = 1;i<=n;i++){
		memset(dp,0,sizeof(dp));
		ans = 0;
		int len =1;
		dp[len] = -r[1]; 
		for(int p =2;p<=i;p++){ // 計算從 r[1]~ r[i] 的最長不上升子序列 
			if(r[p]<=-dp[len]){
				dp[++len] = -r[p];
			}
			else{
				int pos = upper_bound(dp+1,dp+len+1,-r[p])-dp;
				dp[pos] = -r[p];
			}
		}
		ans = len;
		len = 1; // LIS 最大值 
		dp[i+len] =r[i];
		for(int p = i+1;p<=n;p++){ //計算 從 r[i]~ r[n]的最長不下降子序列 
			if(r[p]>=dp[i+len]){
				dp[++len+i] = r[p];
			}
			else{
				int pos = upper_bound(dp+i+1,dp+i+len+1,r[p])-dp;
				dp[pos] = r[p];
			}
		}
		//cout<<len<<"\n\n";
		if(len+ans-1>=M){
			M =len+ans-1;
		}
	}
	cout<<n-M<<"\n";
	return 0;
}

方法3

總體複雜度爲O(n2)O(n^2)

#include<iostream>
#include<stdio.h> 
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1010];
int r[1010];
int main(){
	freopen("in.txt","r",stdin);
	int n;
	cin>>n;
	int index = 0;
	for(int i = 1;i<=n;i++){
		cin>>r[i];
	}
	int M = 0;
	int ans = 0;
	for (int i = 1;i<=n;i++){
		ans = 0;
		memset(dp,0,sizeof(dp)); 
		for(int p =1;p<=i;p++){
			dp[p] = 1;//  單個節點也可視爲長爲1的序列,初始化爲1  
			for(int q = 1;q<p;q++){
				if(r[p]<=r[q]){
					dp[p] = max(dp[p],dp[q]+1);
				}
			}
			ans = max(ans,dp[p]);
		}
		int len = 0;
		for(int p = i;p<=n;p++){
			dp[p] =1;
			for(int q =i;q<p;q++){
				if(r[p]>=r[q]){
					dp[p] = max(dp[p],dp[q]+1);
				}
			}
			len = max(len,dp[p]);
		}
		if(len+ans-1>=M){
			M =len+ans-1;
		}
	}
	cout<<n-M<<"\n";
	return 0;
}

方法4

在這裏插入圖片描述
官方推薦做法,總體複雜度爲O(n2)O(n^2),
引用出處

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[1010];
int dp2[1010];
int dp1[1010];
int n;
int main()
{   
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    memset(dp1,0,sizeof(dp1));
    for(int i=1;i<=n;i++)
    {dp1[i]=1;
        for(int j=1;j<i;j++)
        {
            if(a[j]>=a[i])dp1[i]=max(dp1[i],dp1[j]+1);
        }
    }
    memset(dp2,0,sizeof(dp2));
    for(int i=n;i>=1;i--)
    {dp2[i]=1;
        for(int j=n;j>i;j--)
        {
            if(a[j]>=a[i])dp2[i]=max(dp2[i],dp2[j]+1);
        }
    }
    int ans[1010];
    for(int i=1;i<=n;i++)
        {
            ans[i]=n-(dp1[i]+dp2[i]-1);
        }
    int minn=0x3f3f3f3f;
        for(int i=1;i<=n;i++)
        {
            if(minn>ans[i])minn=ans[i];
        }
    cout<<minn;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章