最长严格递增子序列算法

代码来源于:http://hi.baidu.com/daoyuanlee/blog/item/f5ccff07e58f69cf7a89473b.html

O(n^2) 算法的思想

基于动态规划:用数组a记录数字序列,数组b记录各a各个前缀子序列最长严格递增子序列的长度(即b[i]记录的是a[0]...a[i]的最长严格递增子序列的长度)

显然有b[0]=1,即a[0]的最长严格递增子序列长度显然为1

在这个情况下进行增长,a[1]如果比a[0]大,那么b[1]就为b[0]+1=2. 否则b[1]仍然为1(即最长严格递增子序列为a[0]或a[1])

继续增长至a[0],a[1],...a[i-1]的情况,此时b中下标0至i的部分也存储了长度由1至i-2的a的前缀子序列最长严格递增子序列的长度。

此时我们从0至i-1迭代,并维护一个max变量:

1 int max = 0;
2  for (j = 0; j < i; j ++)
3 if (max < b[j] && a[j] < a[i]) max = b[j];
4 b[i] = max + 1;

迭代过程中维护一变量max,迭代中,当满足以下2条件时更新max:

1. max < b[j]

2. a[j] < a[i]

使得max取到的是b[0]...b[i-1]中的最大值(假设为b[x]),即a[0]...a[i-1]的最长严格递增子序列的长度;且有a[x]<a[i],即下一个增长到尾部的元素可以为增加当前最长严格递增子序列的长度。

因此a[0]...a[i]的最长严格递增子序列的长度为max+1.

增长持续至整个序列都被加入后,只需要遍历b,取出其中最大的值,即为a的最长严格递增子序列的长度。

O(n*logn)算法

#include <iostream>

using namespace std;

const int MAX = 100;
int b[MAX];

int bs(int x,int k)
{
if(x < b[1]) return 1;
int left = 1, right = k, mid;
while(left < right-1)
{
mid
= (left+right)/2;
if(b[mid] <= x) left = mid;
else right = mid;
}
return right;
}

int LIS(int n, int a[])
{
int k = 1;
b[
1] = a[0];
for(int i = 1; i < n; ++i)
{
if(a[i] > b[k]) b[++k] = a[i];
else if(a[i] != b[k]) b[bs(a[i], k)] = a[i];
}
return k;
}

int main()
{
int n, i, a[MAX];
while(scanf("%d", &n) == 1)
{
for(i = 0; i < n; ++i) scanf("%d", &a[i]);
printf(
"%d\n", LIS(n, a));
}
return 0;
}

原文地址:https://www.cnblogs.com/mdyang/p/2031282.html