假设一个数组= {2,5,7,8,10}。您需要找到最长增加子序列的长度,以使元素不小于它之前所有元素的总和。
在这种情况下,答案可以是{2,5,7},{2,5,8}或{2,8,10}。所以长度= 3
这很容易在O(n ^ 2)中解决。由于LIS长度可以在O(n log n)中找到。因为问题只是询问长度,所以,我认为这个问题在O(n log n)中也是可以解决的。但是我该怎么做呢?
答案 0 :(得分:0)
有一个O(N^2)
动态编程解决方案,如:
让f(i, j)
为“正确”子序列以最后i
个元素之一结尾且由j
个元素组成的最小总和。
基本情况为f(0, 0) = 0
(空前缀,无元素)
转换为f(i, j) -> f(i + 1, j)
(不添加新元素)和
f(i, j) -> f(i + 1, j + 1) if a[i] > f(i, j)
(如果我们可以的话,将i
- 元素添加到子序列的末尾。
这种解决方案的正确性是不言而喻的。
一个很酷的事实:让A
成为k
元素的“正确”子序列。比A
的最后一个元素不小于max(1, 2^(k-2))
(证据:k = 1
和k = 2
的情况。现在我们可以使用归纳和{{1}的事实}})
因此,1 + sum i = 0 .. k of 2^k = 2^(k+1)
在上述动态编程解决方案中的范围超过j
,因此它适用于0..log MAX_A + C
。
O(N * log MAX_A)
不是O(N * log MAX_A)
,但此解决方案可以用于实际目的。
答案 1 :(得分:0)
实际上你根本不需要DP解决方案 首先按非递减顺序对数字进行排序。并从左到右循环。跟踪当前的总和 如果下一个数字不小于总和,则将其添加到LIS。否则进入下一个号码 可以证明贪婪的解决方案是最佳解决方案。自己证明;)