您的位置:首页 > 其它

最长递增子序列(LIS)的两种实现

2013-04-09 09:38 399 查看

最长递增子序列(LIS)

1.最长递增子序列的问题描述
给定一序列L=(a1,a2,a3,a4......an-1,an),存在序列L'=(ai1,ai2,ai3......aik)满足ai1<ai2<ai3......<aik,且i1<i2<i3<......<ik。则称L'是序列L的一个递增子序列,显然最长递增子序列就是,所有满足这个条件的序列里面长度最大的。
2.有两种算法解决
方法(1).用一个序列L1保存L排序后的结果,然后找L1和L的最长公共子序列。(在这里不涉及,主要讲方法二的两个实现)
方法(2).动态规划实现。由于简单递推公式直接给出。opt[i]表示以ai为结束时的最长子序列的长度。
所以opt[0] = 1,当i > 0时:opt[i] = max {opt[j]+1,1}(j<i,且a[j] < a[i])。
int LIS1 (int data[], int n)
{
if (n == 0)
return 0;
int ans = opt[0] = 1;
for (int i = 1; i < n; ++i)
{
opt[i] = 1;
for (int j = 0; j < i; ++j)
{
if (data[i] > data[j])
opt[i] = max(opt[j] + 1, opt[i]);
}
ans = max (opt[i], ans);
}
return ans;
}
以上实现方式算法复杂度为O(n^2).其中在寻找opt[j]时花了O(n)的算法复杂度,可以改用二分查找将算法浮渣度降到O(logn),总的算法复杂度为O(nlogn).其中用到了一个辅助数组,用于保存最大递增子序列的最末元素。实现如下:
int LIS2 (int data[], int len)
{
if (len == 0)
return 0;

for (int i = 0; i < len; ++i)
assit[i] = MAXNUM;

assit[0] = data[0];
opt[0] = 1;
int ans = 1;

int low, high, mid;
for (int  i = 1; i < len; ++i)
{
low = 0;
high = i;
while (low < high)
{
mid = low + ((high - low)>>1);
if (assit[mid] < data[i])
low = mid + 1;
else
high = mid;
}

assit[low] = data[i];
opt[i] = low + 1;
ans = max (opt[i], ans);
}
return ans;
}


POJ2533可以验证此算法的正确性 
AC代码如下:
#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXN = 1002;
const int MAXNUM = 10009;
int data[MAXN];
int assit[MAXN]; //最大递增子序列的最末元素
int opt[MAXN];
int n;

int LIS1 (int data[], int n) { if (n == 0) return 0; int ans = opt[0] = 1; for (int i = 1; i < n; ++i) { opt[i] = 1; for (int j = 0; j < i; ++j) { if (data[i] > data[j]) opt[i] = max(opt[j] + 1, opt[i]); } ans = max (opt[i], ans); } return ans; }

int LIS2 (int data[], int len) { if (len == 0) return 0; for (int i = 0; i < len; ++i) assit[i] = MAXNUM; assit[0] = data[0]; opt[0] = 1; int ans = 1; int low, high, mid; for (int i = 1; i < len; ++i) { low = 0; high = i; while (low < high) { mid = low + ((high - low)>>1); if (assit[mid] < data[i]) low = mid + 1; else high = mid; } assit[low] = data[i]; opt[i] = low + 1; ans = max (opt[i], ans); } return ans; }

int main ()
{
scanf ("%d", &n);

for (int i = 0; i < n; ++i)
scanf ("%d", &data[i]);

printf ("%d", LIS2(data, n));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息