最长递增子序列(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]。
最开始写的程序貌似是对的
可以输出相应的最长递增项
输出时2 5 6 8 9
再看一个扩展问题
设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
相关文章推荐
- Python动态规划求解最长递增子序列(LIS)
- 最长递增子序列(LIS)
- 最长递增子序列(LIS) 学习中ing
- 动态规划(DP),最长递增子序列(LIS)
- 最长递增子序列(LIS)
- 使用动态规划求解最长递增子序列(LIS)
- 最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)
- 最长递增子序列(LIS)问题
- 最长递增子序列问题的求解(LIS)
- 最长递增子序列(LIS)
- Java-LIS最长递增子序列(动态规划实现)
- 关于最长递增子序列问题的求解(LIS)
- 最长递增子序列(LIS)的三种求解方法
- 最长递增子序列(LIS)(转)
- 最长递增子序列(LIS)问题
- 最长公共子序列(LCS)和最长递增子序列(LIS)的求解
- 最长递增子序列问题的求解(LIS)
- 关于最长递增子序列问题的求解(LIS)
- 最长递增子序列(LIS)
- 最长递增子序列(LIS)