algorithm - 有人能解释一下为什么下面的 LIS 算法不是 O(n) 吗?

标签 algorithm erlang dynamic-programming combinatorics lis

以下代码遍历一次链表,找到LIS。我不明白为什么 DP 算法应该采用 O(n2)。

//C
int lis(int *a, int l){
  if(l == 0) return 1;
  else if(a[l] > a[l - 1])  return  1 + lis(a, l - 1);
  else  return lis(a, l - 1);
}

int main(){
  int a[] =  { 10, 22, 9, 33, 21, 50, 41, 60 };
  cout << lis(a, sizeof(a)/sizeof(a[0]) - 1);
}

% erlang
lis([_H]) -> 1;
lis([H1, H2 |T]) when H1 > H2 ->  1 + lis([H2|T]);
lis([_H|T]) -> lis(T).

main() ->  lis(lists:reverse([ 10, 22, 9, 33, 21, 50, 41, 60 ])).

最佳答案

lis/1 函数的当前实现是 O(n),我看不出有任何怀疑的理由。但是有一些问题。您的实现实际上并未计算有效的 LIS。尝试

lis(lists:reverse([1,2,3,4,1,2]))

错误示例。最长递增序列是 [1,2,3,4],对吧?但是您的算法返回 6 作为结果。

  • 您的算法中的第一个错误是您每次都增加 result,当您遇到大于前一个的元素时。但是,只有当当前元素大于当前 LIS 的最大元素 时,您才应该增加 result。所以(根据上面的例子)你应该记住 4 并且在你检测到 2 大于 1 之后不要增加 result >.

  • 但这不仅仅是您必须做的事情。考虑序列 1 2 3 6 4 5。对于 5 个第一个元素,LIS 的长度为 4。但是那里有两个可能的选项 - 1 2 3 41 2 3 6。您应该将哪个作为实际的 LIS?

  • 等等等等......

另一个例子直接来自wiki page.

序列 [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15] 有 LIS [ 0, 2, 6, 9, 13, 15](例如,6 元素),但您的算法显示为 9

而且,(请纠正我,如果我错了),LIS 实现必须返回子序列本身,而不仅仅是它的长度。

关于algorithm - 有人能解释一下为什么下面的 LIS 算法不是 O(n) 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27059302/

相关文章:

algorithm - 检查给定值 AorB 和 APlusB 是否存在 A 和 B

erlang - Windows上的Riak

c++ - 如何将递归解决方案转换为自下而上或自上而下的解决方案?

erlang - 将数据持久保存到本地 mnesia 表中

algorithm - 两个字符串所有可能的LCS(Longest Common Subsequence)

dynamic-programming - 为什么有无界背包构造的一维数组和0/1背包构造的二维数组?

c# - 算法 - 聚合重复记录

java - 在快速排序中使用最后一个元素作为枢轴时无法解决错误

algorithm - Ford-Fulkerson 算法在具有权重 1 的链接的图中

erlang - 压缩 Erlang 节点之间发送的消息