您的位置:首页 > 其它

最长递增子序列(LIS)

2014-12-11 11:11 295 查看
给定一个长度为n的数组,找出一个最长的单调递增子序列(不一定连续,当时先后顺序不能乱)。 更正式的定义是:

设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<ak1,ak2,…,akm>,其中k1<k2<…<km且ak1<ak2<…<akm。求最大的m值。

比如数组A 为{10, 11, 12, 13, 1, 2, 3, 15}, 那么最长递增子序列为{10,11,12,13,15}。

以i结尾的序列的最长递增子序列和其[0, i - 1]“前缀”的最长递增子序列有关,设LIS[i]保存以i结尾的最长递增子序列的长度

若i = 0,则LIS[i] = 1;

若i > 0,则LIS[i]的值和其[0, i - 1]前缀的最长递增子序列长度有关,用j遍历[0, i - 1]得到其最长递增子序列为LIS[j],对每一个LIS[j],如果序列array[j] < array[i]并且LIS[j] + 1 > LIS[i],则LIS[i]的值变成LIS[j] + 1。即:

LIS[i] = max{1, LIS[j] + 1},其中array[i] > array[j] 且 j = [0, i - 1]。

最开始写的程序貌似是对的

#include<iostream>
using namespace std;
//LIS-longest increasing subsequent
int Lis(int arry[],int len){
int *lis=new int[len];
int max=-1;
for(int i=0;i<len;i++){
lis[i]=1;
for(int j=0;j<i;j++){
if(arry[i]>arry[j]&&(lis[j]+1)>lis[i]){//要满足(lis[j]+1)>lis[i],否则不应该加1
lis[i]=lis[j]+1;
}
}
if(lis[i]>max)
max=lis[i];
}

//可以再上个循环中操作
/*	int max=-1;
for(int i=0;i<len;i++){
if(lis[i]>max)
max=lis[i];
}*/
delete []lis;
return max;
}
int main(){
int arry[]={2,1,5 ,3, 6, 4, 8 ,9 ,7};
int len=9;
cout<<Lis(arry,len)<<endl;
system("pause");
return 0;
}


可以输出相应的最长递增项

#include<iostream>
#include<vector>
using namespace std;
//LIS-longest increasing subsequent
int Lis(int arry[],int len){
int *lis=new int[len];
vector<vector<int>>tmp(len);
int max=-1;
for(int i=0;i<len;i++){
lis[i]=1;
for(int j=0;j<i;j++){
if(arry[i]>arry[j]&&(lis[j]+1)>lis[i]){//要满足(lis[j]+1)>lis[i],否则不应该加1
lis[i]=lis[j]+1;
tmp[i].push_back(arry[j]);
}
}
tmp[i].push_back(arry[i]);
if(lis[i]>max)
max=lis[i];
}
for(int i=0;i<len;i++){
if(lis[i]==max){
for(int j=0;j<tmp[i].size();j++){
cout<<tmp[i][j]<<" ";
}
cout<<endl;
}
}
delete []lis;
return max;
}
int main(){
int arry[]={2,1,5 ,3, 6, 4, 8 ,9 ,7};
int len=9;
cout<<Lis(arry,len)<<endl;
system("pause");
return 0;
}


输出时2 5 6 8 9

再看一个扩展问题

1.1从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)

双端LIS问题,用动态规划的思想可以解决,目标规划函数为max{B[i] + C[i]},其中B[i]是从左到右的,0~i个数之间满足递增的数字个数;C[i]为从右到左的,n- 1 ~ i个数之间满足递增的数字个数。最后结果为n - max + 1(+1是因为B[i]和C[i]算重一个)

#include<iostream>
#include<vector>
using namespace std;

//返回最少删除的数个数
int DoubleLis(int arry[],int len){
int max=-1;
int *B=new int[len];
int *C=new int[len];

for(int i=0;i<len;i++){
B[i]=1;
C[i]=1;
}

for(int i=0;i<len;i++){
for(int j=0;j<=i;j++){
if(arry[i]>arry[j]&&B[i]<(B[j]+1)){
B[i]=B[j]+1;
}
}
}

for(int i=len-1;i>=0;i--){
for(int t=len-1;t>=i;t--){
if(arry[i]>arry[t]&&C[i]<(C[t]+1)){
C[i]=C[t]+1;
}
}
}

for(int i=0;i<len;i++){
if((B[i]+C[i])>max)
max=B[i]+C[i];
}

delete []B;
delete []C;
return len-max+1;
}

int main(){
int arry[]={1,4,3,5,6,7,2,0};
int len=8;
cout<<DoubleLis(arry,len)<<endl;

system("pause");
return 0;
}
结果是1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: