最长递增子序列又叫做最长上升子序列;子序列,正如LCS一样,元素不一定要求连续。本节讨论实现三种常见方法,主要是练手。
题:求一个一维数组arr[i]中的最长递增子序列的长度,如在序列1,-1,2,-3,4,-5,6,-7中,最长递增子序列长度为4,可以是1,2,4,6,也可以是-1,2,4,6。
方法一:DP
像LCS一样,从后向前分析,很容易想到,第i个元素之前的最长递增子序列的长度要么是1(单独成一个序列),要么就是第i-1个元素之前的最长递增子序列加1,可以有状态方程:
LIS[i] = max{1,LIS[k]+1},其中,对于任意的k<=i-1,arr[i] > arr[k],这样arr[i]才能在arr[k]的基础上构成一个新的递增子序列。
代码如下:在计算好LIS长度之后,output函数递归输出其中的一个最长递增子序列。
/*
MaxIncreaseSubString.cpp
arr:1 -1 2 -3 4 -5 6 -7
dp:1 1 2 1 3 1 4 1
1234-> 1 2 4 6 || -1 2 4 6
@author arhaiyun
*/
#include "stdafx.h"
#include <iostream>
using namespace std;
const int MAX_LEN = 100;
// dynamic plan assistant array
int* dp = new int[MAX_LEN];
static int lis = 0;
int LIS(const int* data, int length)
{
if(data == NULL || length <= 0)
return 0;
for(int i = 0; i < length; i++)
{
dp[i] = 1;
for(int j = 0; j < i; j++)
{
if(data[i] > data[j] && dp[i] < dp[j] + 1)
{
dp[i] = dp[j] + 1;
if(dp[i] > lis)
lis = dp[i];
}
}
}
cout<<"LIS:"<<lis<<endl;
return lis;
}
void PrintLIS(int* data, int index)
{
if(data == NULL || index < 0 || lis == 0)
return;
bool isLIS = false;
if(dp[index] == lis)
{
isLIS = true;
lis--;
}
PrintLIS(data, index - 1);
if(isLIS)
{
cout<<data[index]<<" ";
}
}
int main(int argc, char* argv[])
{
int data[] = {1, -1, 2, -3, 4, -5, 6, -7};
int length = sizeof(data) / sizeof(int);
LIS(data, length);
PrintLIS(data, length - 1);
system("pause");
return 0;
}