【发布时间】:2018-10-17 19:03:16
【问题描述】:
我只是从算法开始,我试图找出下面 while 循环的运行时间,以 'n' 表示。
int k=1;
while(k<n-k){
k+=k;
}
这里 n>2。我知道 k 的值每次都会翻倍,并且循环只运行一次,一旦 k 值大于 n/2。但是我很难用“n”来表达。
【问题讨论】:
标签: c++ algorithm time-complexity
我只是从算法开始,我试图找出下面 while 循环的运行时间,以 'n' 表示。
int k=1;
while(k<n-k){
k+=k;
}
这里 n>2。我知道 k 的值每次都会翻倍,并且循环只运行一次,一旦 k 值大于 n/2。但是我很难用“n”来表达。
【问题讨论】:
标签: c++ algorithm time-complexity
值得列出重点:
k 在每次循环迭代中翻倍
您的循环条件可以重写为:while(2*k < n)*
基本问题是:我必须 加倍k 多少次,直到 k 加倍 等于或大于 @987654325 @?
这很容易。这正是对数的工作原理。以号码2 为例。我必须翻倍多少次才能达到,比如说,1000?答案是 log21000 向上取整。
本质上,您的算法是log_2(n) - 1,这意味着您的算法以对数时间复杂度运行。
*正如 François Andrieux 在他的评论中正确陈述的那样,虽然这个陈述在数学上是正确的,但由于数据类型的表示限制,编程中并非总是如此。对于较大的ks,表达式2*k 可能会导致溢出并使整个表达式无效,而对于相同的输入,表达式k < n-k 将正常运行。
【讨论】:
k 是signed int,2*k < n 并不完全等同于k < n-k,因为如果n 足够大,第一个表单可能会溢出。
替换
while(k<n-k)
k+=k;
等价
while(2*k<n)
k*=2
最后一个肯定是O(log(n)) - 它使log2(n)-1 步骤
【讨论】:
表达式k < n-k 简化为k < n/2。
时间复杂度应为O(log(n)),基数为 2
K = 1 -> 2 -> 4 -> 8 -> ... -> m iterations
2^(m-1) < n/2
m-1 < log2(n/2)
m ~ log2(n)
【讨论】: