最长上升子序列,LIS<DP+二分>

xiaoxiao2021-02-27  327

例子如4,1,6,2,8,5,7,3

8个数,如何求其最长上升子序列呢。

可以用L[i]表示前面子序列长度为i+1(因为length的下标从0开始)尾元素的最小值。

A[i]装的是每个元素的值。

length=1;

初始化L[0]=A[0].

for i=0 to n-1

if|(L[length-1]<A[I])

L[length++]=A[i];//表明最长的子序列的尾元素小于A[I],那么就可以更新这个尾元素,并且最长子序列长度++

else //说明这个数小于尾元素

for(j=0,1,2,length-1)到length-1是因为L[length-1]就 为目前最长子序列的尾元素

L数组一定为递增顺序,因为添加时候一定比之前的L[length-1]大才能添加新的length

找到第一个大于A[i]的元素,将其L[j]=A[i]后break即可。(仔细想想)这么更新是为了这个长度的尾元素只要最小的那一个,但只能更新一个。

二分的重点:找满足某条件的最大/最小值该怎么二分。

#include<iostream> #include <stdio.h> #include <string.h> #include <set> #include <vector> #include <stdlib.h> #include<direct.h> #include <io.h> #include <direct.h> using namespace std; int L[500]; int A[500]; int main(){ freopen("in.txt","r",stdin); int i,j,k,f1,f2,f3,t1,t2,t3,n,m,T,t; cin >> n; for(i=0;i<n;i++) cin >> A[i]; memset(L,0,sizeof(L)); L[0]=A[0]; int length=1; for(i=1;i<n;i++) if(L[length-1]<A[i]){ L[length++]=A[i]; cout << length <<" " << i<< endl; }else{ int left1,right1,mid1,min1; min1=1e9+7; left1=0;right1=length-1;//从0更新到length-1 while(right1>=left1){ mid1=(right1+left1)/2; if(L[mid1]<=A[i]) left1=mid1+1; else{ right1=mid1-1; min1=min(mid1,min1); } } L[min1]=A[i]; } cout << length << endl; return 0; }

转载请注明原文地址: https://www.6miu.com/read-1959.html

最新回复(0)