求序列的最长递增子序列

bazookier 2008-06-01 10:10:56
请给出一个O(nlgn)时间的算法,使之能找出一个n个数的序列中最长的单调递增子序列。(提示:观察长度为i的一个候选子序列的最后一个元素,它至少与长度为i-1的一个候选子序列的最后一个元素一样大。通过把候选子序列与输入序列相连接来维护它们)。
...全文
1240 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
dzrjojo 2008-11-07
  • 打赏
  • 举报
回复
good
michaelwangwh 2008-06-03
  • 打赏
  • 举报
回复
动态规划,10年前就碰到这样的题目了,拦截导弹,太经典了
  • 打赏
  • 举报
回复
啥也不说了,直接上图:



bazookier 2008-06-02
  • 打赏
  • 举报
回复
看不懂,知道是对的但不知道为什么。英文解释太抽象了,没看明白。希望给解释下。
可口可乐 2008-06-01
  • 打赏
  • 举报
回复
参考网页
http://www.algorithmist.com/index.php/Longest_Increasing_Subsequence

Faster Algorithm

There's also an O(nlogn) solution based on some observations. Let Ai,j be the smallest possible tail out of all increasing subsequences of length j using elements a_1, a_2, a_3, \ldots, a_i.

Observe that, for any particular i, A_{i,1} < A_{i,2} < \ldots < A_{i,j}. This suggests that if we want the longest subsequence that ends with ai + 1, we only need to look for a j such that Ai,j < ai + 1 < = Ai,j + 1 and the length will be j + 1.

Notice that in this case, Ai + 1,j + 1 will be equal to ai + 1, and all Ai + 1,k will be equal to Ai,k for k \ne j + 1.

Furthermore, there is at most one difference between the set Ai and the set Ai + 1, which is caused by this search.

Since A is always ordered in increasing order, and the operation does not change this ordering, we can do a binary search for every single a_1, a_2, \ldots, a_n.


#include <vector>
using namespace std;

/* Finds longest strictly increasing subsequence. O(n log k) algorithm. */
template<typename T> vector<int> find_lis(vector<T> &a)
{
vector<int> b, p(a.size());
int u, v;

if (a.size() < 1) return b;

b.push_back(0);

for (int i = 1; i < (int)a.size(); i++) {
if (a[b.back()] < a[i]) {
p[i] = b.back();
b.push_back(i);
continue;
}

for (u = 0, v = b.size()-1; u < v;) {
int c = (u + v) / 2;
if (a[b[c]] < a[i]) u=c+1; else v=c;
}

if (a[i] < a[b[u]]) {
if (u > 0) p[i] = b[u-1];
b[u] = i;
}
}

for (u = b.size(), v = b.back(); u--; v = p[v]) b[u] = v;
return b;
}

/* Example of usage: */
#include <cstdio>
int main()
{
int a[] = { 1, 9, 3, 8, 11, 4, 5, 6, 4, 19, 7, 1, 7 };
vector<int> seq(a, a+sizeof(a)/sizeof(a[0]));
vector<int> lis = find_lis(seq);

for (unsigned i = 0; i < lis.size(); i++)
printf(i+1 < lis.size() ? "%d " : "%d\n", seq[lis[i]]);

return 0;
}
Yoon_EunHae 2008-06-01
  • 打赏
  • 举报
回复
是公共递增子序列? 这个最快的算法是nlogn的 2分搜索
还是某个串递增子序列? 这个可以线性规划的0(n)
经典的dp题,算法到处都是..!
wuyi8808 2008-06-01
  • 打赏
  • 举报
回复
比较麻烦,看看算法的书。
zjk2752 2008-06-01
  • 打赏
  • 举报
回复
不明白你那提示是什么意思

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧