java - 这个片段有 O(log^2(n)) 复杂度吗?
问题描述
如果不是,那会是女巫的复杂性吗?谢谢:
public static int f(int n, int x) {
for (int i = n; i > 0; i /= 2) {
for (int j = 0; j < i; j++) {
x += j; // Assume, this operation costs 1.
}
}
return x;
}
解决方案
这是一个有趣的。的假设log^2(n)
是错误的。亨利很好地减少了荒谬,为什么不能log^2(n)
在评论中:
- 我们可以看到,
O(log^2(n)) ⊊ O(n)
. - 内部循环的第一次迭代需要
O(n)
. - 因为
O(log^2(n)) ⊊ O(n)
,假设一定是错误的,因为仅第一次迭代就是∈ O(n)
.
这也为我们提供了算法的下界:由于算法的第一次迭代是∈ O(n)
,那么整个算法至少需要Ω(n)
。
现在让我们来估计执行时间。通常,第一种方法是分别估计内环和外环并将它们相乘。显然,外循环具有复杂性log(n)
。然而,估计内部循环并非易事。所以我们可以用n
(这是一个高估)来估计它并得到n log(n)
. 这是一个上限。
为了得到更精确的估计,让我们做两个观察:
- 内循环基本上将外循环变量的所有值相加
i
- 循环变量
i
遵循n
,n/2
,n/4
, ...,1
,的模式0
让我们假设n = 2^k, k ∈ ℕ, k > 0
ien
是 的幂2
。然后n/2
= 2^(k-1)
, n/4 = 2^(k-2)
, ... 从这个假设推广,如果n
不是 的幂2
,我们将其设置为 的下一个较小的幂2
。事实上,这是一个准确的估计。我将关于为什么的推理留给读者作为练习。
众所周知的事实是2^k + 2^(k-1) + 2^(k-2) + ... + 1 (+ 0) =
sum_(i=0)^k 2^i = 2^(k+1) - 1
。由于我们的输入是n = 2^k
,我们知道这一点2^(k+1)= 2 * 2^k = 2 * n ∈ O(n)
。该算法的运行时复杂度实际上是Θ(n)
,即这是一个上限和一个下限。它也是一个下限,因为我们所做的估计是准确的。或者,我们可以使用我们对算法存在的观察,∈ Ω(n)
从而以这种方式到达Θ(n)
。
推荐阅读
- continuous-integration - Download GitLab Generic Package File using Deploy Token
- mongodb - Mongodb - Setting the replication at the db or collection level
- java - How do I calculate years until graduation for a user's input?
- r - How can I exclude pieces of data in R?
- linux - jupyter notebook can't detect conda kernels only on boot
- windows - How to create destination folder with date appended to it via Powershell?
- python - Python - 将excel数据迭代为登录功能的变量
- sequelize.js - Sequelize - 通过动态表单更新记录
- python - 随机组合两个列表
- c++ - 条件观察点监控lldb中指针的内容