这似乎是动态规划的一个问题。构建数组时,您会构建另一个数组,其中包含每个特定索引的累积总和。所以i
该数组中的每个都有来自 的总和1..i
。
现在很容易看出索引值的总和p..q
是SUM(q) - SUM(p-1)
(在特殊情况下SUM(0)
是0
)。显然我在这里使用基于 1 的索引......这个操作是 O(1),所以现在你只需要一个 O(n) 算法来找到最好的。
一个简单的解决方案是跟踪 ap
并q
在数组中遍历它们。你开始扩展q
。然后你反复收缩p
和扩张q
,就像毛毛虫在你的阵列中爬行。
展开q
:
p <- 1
q <- 1
while SUM(q) - SUM(p-1) < K
q <- q + 1
end while
现在q
是子数组和刚刚超过(或等于)的位置K
。子数组的长度为q - p + 1
。
在q
循环之后,您测试子数组长度是否小于您当前的最佳长度。然后你前进一步p
(这样你就不会意外跳过最佳解决方案)并再次前进。
您实际上并不需要创建SUM
数组...您可以随时构建子数组总和...您需要返回使用“真实”p
而不是之前的那个。
subsum <- VAL(1)
p <- 1
q <- 1
while q <= N
-- Expand
while q < N and subsum < K
q <- q + 1
subsum <- subsum + VAL(q)
end while
-- Check the length against our current best
len <- q - p + 1
if len < bestlen
...
end if
-- Contract
subsum <- subsum - VAL(p)
p <- p + 1
end while
笔记:
j_random_hacker 说:这将有助于准确解释为什么只检查该算法检查的 O(n) 个不同子数组而不是所有 O(n^2) 个可能的不同子数组是可以接受的
动态规划的哲学是:
- 不要遵循会导致非最佳结果的解决方案路径;和
- 使用先前解决方案的知识来计算新的解决方案。
在这种情况下,通过对元素求和来计算单个解决方案候选者(一些(p,q)
这样的)。p <= q
因为这些元素是正整数,所以我们知道对于任何候选(p,q)
解,候选解(p,q+1)
都会更大。
所以我们知道如果(p,q)
是一个最小的解决方案,那么(p,q+1)
就不是。一旦我们有一个候选人,我们就会结束我们的搜索,并测试那个候选人是否比我们迄今为止看到的任何一个更好。这意味着对于每个p
,我们只需要测试一个候选人。这导致两者都增加p
并且q
只会增加,因此搜索是线性的。
另一部分(使用以前的解决方案)来自于认识到这一点sum(p,q+1) = sum(p,q) + X(q+1)
和类似sum(p+1,q) = sum(p,q) - X(p)
的。因此,我们不必对每一步之间的p
所有元素求和。q
每当我们推进其中一个搜索指针时,我们只需要加或减一个值。
希望有帮助。