问题描述:
求数组中最长递增子序列
例如:
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;
}
来源:https://www.cnblogs.com/luosongchao/p/3551445.html