问题描述:
求数组中最长递增子序列
例如:
1,-1,2,-3,4,-5,6,-7
最长递增子序列为:1,2,4,6
问题解决:
对于这类最优化问题,可以考虑使用动态规划,需要查看问题是否满足动态规划的最优化原理和无后效性。显然最长递增子序列中的部分子序列也是最长递增子序列,满足最优化原理
无后效性,对于最长递增子序列中的元素,其前面的元素,不会影响到其后的元素,满足无后效性,因此可以使用动态规划。
方法一:
将数组从小到大排序,设为arrayB,求解原数组arrayA的最长递增子序列的问题转换为求解arrayA与arrayB的最长公共子序列,复杂度O(nlogn+n^2)=O(n^2)
方法二:
设数组array[]中前i个元素的最长递增子序列长度为LIS[i],那么
LIS[i+1]=max{1,LIS[k]+1},for any k<=i & array[i+1]>array[k]
方法三:
方法二考察第i+1个元素时没有考虑前i个元素的分布,现在考虑前i个元素的分布。假设LIS[i]表示数组array[]中前i个元素最长递增子序列长度,MaxV[j],表示长度为j的所有递增子序列中最大值的最小值,那么:
对前i个元素的任何一个递增子序列,如果这个子序列的最大元素比array[i+1]小,则将array[i+1]添加到该子序列中,构成一个新的递增子序列。
具体实现:
/** * 求解数组的最长递增子序列 * * 问题满足动态规划的最优化原理和无后效性,可以使用动态规划来求解 * * 假设在目标数组array[]的前i个元素中,最长递增子序列长度为LIS[i],那么: * LIS[i+1]=max{1,LIS[k]+1},array[i+1]>array[k],for any k<=i 也就是说,如果array[i+1] * 大于array[k],那么第i+1个元素可以接在LIS[k]长的子序列后面构成一个更长的子序列。 * array[i+1]本身至少可以构成一个长度为1的子序列。 */ #include <iostream> using namespace std; int MaxLIS(int* array,int size) { int max=array[0]; for (int i=0;i<size;i++) { max=array[i]>max?array[i]:max; } return max; } /** * 方法1:求解最长递增子序列的算法,复杂度O(N^2) * 求解思路: * LIS[i+1]=max{1,LIS[k]+1},for any k<=i */ int LIS1(int array[],int size) { int* LIS=new int[size]; for (int i=0;i<size;i++) { LIS[i]=1; //执行:LIS[i+1]=max{1,LIS[k]+1},for any k<=i for (int j=0;j<i;j++) { if (array[i]>array[j]&&LIS[j]+1>LIS[i]) { LIS[i]=LIS[j]+1; } } } return MaxLIS(LIS,size); } /** * 方法2:求解最长递增子序列算法2,复杂度O(N^2) * 求解思路: * 方法1,考察第i+1个元素的时候,没有考虑前i个元素的分布情况。现在考察第i+1个元素 * 的时候考虑前面i个元素的情况,即对于前面i个元素的任何一个递增子序列,如果这个子序列的 * 最大的元素比array[i+1]小,则将array[i+1]添加到这个子序列的后面,构成一个新的递增子序列 */ int LIS2(int* array,int size) { int* maxV=new int[size+1]; //记录长度为k的子序列的最大元素为maxV[k] maxV[1]=array[0]; maxV[0]=array[0]-1; //简化数组 int* LIS=new int[size]; for (int i=0;i<size;i++) { LIS[i]=1; } int nmaxLIS=1; //最长递增子序列长度 for (int i=0;i<size;i++) { int j=nmaxLIS; //寻找array[i]需要添加的最长递增子序列 for (;j>=0;j--) { if (array[i]>maxV[j]) { LIS[i]=j+1; break; } } //array[i]添加到当前最长递增子序列 if (LIS[i]>nmaxLIS) { nmaxLIS=LIS[i]; maxV[nmaxLIS]=array[i]; } else //更新指定最长递增子序列长度,其中maxV[j]<array[i]<maxV[j+1] { maxV[j+1]=array[i]; } } return nmaxLIS; } int main() { int array[]={1,-1,2,-3,4,-5,6,-7}; int size=sizeof(array)/sizeof(array[0]); cout<<"最长递增子序列长度Method1:"<<LIS1(array,size)<<endl; cout<<"最长递增子序列长度Method2:"<<LIS2(array,size)<<endl; }