您的位置:首页 > 其它

最长上升子序列LIS算法粗略讲解

2016-08-09 14:51 232 查看

定义

LIS(Longest Increasing Subsequence)最长上升(不下降)子序列,有两种算法复杂度为O(n*logn)和O(n^2)。在上述算法中,若使用朴素的顺序查找在D1..Dlen查找,由于共有O(n)个元素需要计算,每次计算时的复杂度是O(n),则整个算法的时间复杂度为O(n^2),与原来算法相比没有任何进步。但是由于D的特点(2),在D中查找时,可以使用二分查找高效地完成,则整个算法时间复杂度下降为O(nlogn),有了非常显著的提高。需要注意的是,D在算法结束后记录的并不是一个符合题意的最长上升子序列!算法还可以扩展到整个最长子序列系列问题。

问题描述:给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <cmath>
#include <queue>
using namespace std;
const int maxn=1e3+10;
int n,a[maxn],dp[maxn];
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
{
scanf("%d",a+i);
dp[i]=1;
}
for(int i=1;i<n;i++)
{
for(int j=0;j<i;j++)
{
if(a[i]>a[j])
{
dp[i]=max(dp[i],dp[j]+1);
}
}
}
int maxi=0;
for(int i=0;i<n;i++)
{
printf("sss  i=%d   dp[i]=%d\n",i,dp[i]);
maxi=max(maxi,dp[i]);
}
printf("%d\n",maxi);
}
return 0;
}


(nlogn):维护一个一维数组c,并且这个数组是动态扩展的,初始大小为1,c[i]表示最长上升子序列长度是i的所有子串中末尾最小的那个数,根据这个数字,我们可以比较知道,只要当前考察的这个数比c[i]大,那么当前这个数一定能通过c[i]构成一个长度为i+1的上升子序列。当然我们希望在C数组中找一个尽量靠后的数字,这样我们得到的上升子串的长度最长,查找的时候使用二分搜索,这样时间复杂度便下降了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <cmath>
#include <queue>
using namespace std;
int n,a[40005],dp[40005],b[40005];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
dp[i]=1;
}
int l,r,mid,maxi=0,len=0;
for(int i=1;i<=n;i++)
{
int num=a[i];
l=1;
r=len;
while(l<=r)
{
mid=(l+r)>>1;
if(num>b[mid])
l=mid+1;
else
r=mid-1;
}
b[l]=num;
dp[i]=l;
if(l>len)
len=l;
if(dp[i]>maxi)
maxi=dp[i];
}
printf("%d\n",maxi);
}
return 0;
}


END!!!!!!!!!!!!!!!!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: