【发布时间】:2010-12-05 15:12:06
【问题描述】:
我需要找到以下片段的大O运行时间:
sum =0;
for (int i=1; i<n; i++) {
for (int j=1; j< n/i; j++) {
sum = sum +j;
}
}
我知道外循环是 O(n),但我在分析内循环时遇到问题。我认为它是 O(log n)。
【问题讨论】:
我需要找到以下片段的大O运行时间:
sum =0;
for (int i=1; i<n; i++) {
for (int j=1; j< n/i; j++) {
sum = sum +j;
}
}
我知道外循环是 O(n),但我在分析内循环时遇到问题。我认为它是 O(log n)。
【问题讨论】:
正如 Dave 所说,它是 O(n log n),因为内部循环是 O(log n)。
【讨论】:
让我们用这种伪数学风格来写吧。
sum i <- [1..n] (sum j <- [1..n/i] 1)
内循环(求和)需要
n / i
迭代,这使得整个术语
sum i <- [1..n] (n/i)
根据分配律化简和:
n * (sum i <- [1..n] (1/i))
内部和在很大程度上类似于1/x 上的积分,它是对数。
所以O(n log n) 是对的。
【讨论】:
解决这个问题的最佳方法是考虑算法将采取多少步。
如果你有 n 个元素,你就知道外层循环至少要运行 n 次。所以它必须至少是 O(n)。
对于每个 i,内部循环必须运行多少次?它会随着 i 的增加而增加、保持不变还是减少?
很明显,内循环的步数会随着 i 的增加而减少,更重要的是,它会非线性地减少。所以你知道它没有 O(n^2) 那么糟糕。
所以它介于 O(n) 和 O(n^2) 之间......关于内部循环中的步骤如何减少的更多分析应该会让你到达那里。编辑:......虽然看起来人们已经放弃了它:)
【讨论】:
n-i 步骤的情况(在插入排序算法等中就是这种情况)。
for i in 1..n for j in 1..i ... 怎么样?根据你的解释,这不是as bad as O(n²),因为内部循环范围随着 i 的增加而减小,但它实际上是 O(n²)