求一维数组中的最长递增子序列,也就是着一个标号的序列 b[0],b[1],…,b[m] ( 0 <= b[0] < b[1] < … < b[m] < N ),使得 array[b[0]] < arrary[b[1]] < … < array[b[m]].
Sample思路
分析目标串:1,-1,2,-3,4,-5,6,-7。
使用i来表示当前遍历的位置:
当i=1,显然最长的递增序列为(1),序列长度为1。
当i=2,由于-1<1。因此需要丢弃第一个值重新建立串(-1),当前长度仍为1。
当i=3,由于2>1,2>-1。因此,最长序列为(1,2),(-1,2),长度为2。
依次类推之后,
假设在目标数组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]长的子序列后面构成一个更长的子序列。
Optimize思路
前面的分析是,当考察第i+1个元素的时候,我们不考虑前面i个元素的分布情况。现在我们从另一个角度分析,在考察第i+1个元素的时候同时考虑前面i个元素的情况。
对于前面i个元素的任何一个递增子序列,如果这个子序列的最大元素比array[i+1]小,那么就可以将array[i+1]加在这个子序列后面,构成一个新的递增子序列。
比如当i=4的时候,目标序列为1,-1,2,-3,4,-5,6,-7最长递增子序列有(1,2),(-1,2)。那么只要4>2,就可以把4直接增加到前面的子序列。
因此,我们需要找到前i个元素中的一个递增子序列,使得这个递增子序列的最大元素比array[i+1]小,且长度尽量地长。
仍然假设在数组的前i个元素中,以array[i]为最大元素的最长递增子序列的长度为LIS[i]。
同时,假设:
长度为1的递增子序列最大元素的值为MaxV[1];
长度为2的递增子序列最大元素的值为MaxV[2];
……
长度为LIS[i]的递增子序列最大元素的值为MaxV[LIS[i]]。
#include <stdio.h>
const int INF=100000000;
int Max(int a,int b){
return a>b?a:b;
}
// O(N^2+N) = O(N^2)
int LIS_Sample(int* array,int n){
int *LIS = new int[n]; //前i个元素中,最长递增子序列的长度为LIS[i]
int Max_LIS = 1;
for(int i=0;i<n;i++){
LIS[i] = 1;
for(int j=0;j<i;j++){ //前面最长的序列
if(array[i] > array[j])
LIS[i] = Max(LIS[i],LIS[j]+1);
}
Max_LIS = Max(Max_LIS,LIS[i]);
}
delete LIS;
return Max_LIS;
}
int LIS_Optimize(int* array,int n){
int *MaxV = new int[n+1]; //保存长度为i的递增子序列最大元素的值
int *LIS = new int[n]; //以array[i]为最大元素的最长递增子序列的长度为LIS[i]
int Max_LIS = 1; //数组最长递增子序列的长度
MaxV[0] = -INF;
MaxV[1] = array[0];
//初始化最长递增序列的信息;
for(int i=0;i<n;i++)
LIS[i] = 1;
for(int i=1;i<n;i++){
//遍历历史最长递增序列信息
int j=0;
for(int j = Max_LIS; j>=0;j--){
if(array[i] > MaxV[j]){
LIS[i] = j+1;
break;
}
}
//如果当前最长序列大于最长递增序列长度,更新最长信息
if(LIS[i] > Max_LIS){
Max_LIS = LIS[i];
MaxV[LIS[i]] = array[i];
}
else if(MaxV[j]<array[i] && array[i] < MaxV[j+1]){
MaxV[j+1] = array[i];
}
}
/*
//打印序列
stack<int> s;
s.push(array[max_index]);
int len = 1;
int last = array[max_index];
for(int i=max_index-1;i>=0;i--){
if(LIS[i] == (Max_LIS-len) && array[i] < last)
s.push(array[i]),len++;
}
while(!s.empty()){
printf("%d ",s.top());
s.pop();
}
printf("\n");
*/
return Max_LIS;
}
int main(){
int a[8] = {1,-1,2,-3,4,5,6,-7};
printf("Sample calculate the longest length is %d\n",LIS_Sample(a,8));
printf("Optimize calculate the longest length is %d\n",LIS_Optimize(a,8));
return 0;
}