最长递增子序列(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;
}
相关文章推荐
- Java-LIS最长递增子序列(动态规划实现)
- 两种Oracle数据库批量插入方法:在mybatis实现,带序列。
- 动态规划:求解最长递增子序列(LIS)
- hdu 4521 小明系列问题——小明序列 (间隔至少为d的LIS 两种解法)
- 最长公共子序列(LCS)和最长递增子序列(LIS)的求解
- 最长递增子序列问题—LIS
- 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现
- 最长递增子序列(LIS)
- 最长递增子序列(LIS)
- 最长递增子序列(LIS)的三种求解方法
- LIS 最长递增子序列 Java的简单实现
- 最长递增子序列 LIS
- 最长递增子序列(LIS)
- 使用动态规划求解最长递增子序列(LIS)
- 最长递增子序列问题,O(N*logN)实现
- 最长递增子序列(LIS)
- 实现全排列的两种算法:字典序列法以及递归算法(java)
- python序列插入的两种实现
- 最长递增子序列(LIS)问题
- 最长递增子序列(LIS)