给出此算法:
m = 1
while(a>m*b){
m = m*2
}
while(a>=b){
while(a>=m*b){
a = a-m*b
}
m=m/2
}
我的问题:该算法的时间复杂度是多少?
我所做的事情:我必须查找说明的数量。所以我发现,第一次,大约有m = log_2(a / b)次迭代。现在在算法第二部分的内部,我发现了这种模式:a_i = a-i * m其中,i是迭代次数。因此内部while有a / bm迭代。
但是我现在不知道如何计算外部,因为条件取决于内部对a所做的操作。
答案 0 :(得分:2)
让我们以与您的previous question中相同的方式“规范化” 开始,请注意,a
中的所有变化和停止条件再次与{ {1}}:
b
不幸的是,这就是相似性结束的地方...
代码段1)
请注意,n = a/b
// 1)
m = 1
while(n>m){
m = m*2
}
// 2)
while(n>=1){
while(n>=m){
n = n-m
}
m=m/2
}
可以写为2的整数次幂,因为它会使每个循环加倍:
m
从停止状态开始:
代码段2)
此处i = 0
while (n > pow(2, i)) {
i++
}
// m = pow(2, i)
的减小与 1)相反,因此它可以再次写成2的幂:
m
内部循环比上一个问题的内部循环更简单,因为// using i from the end of 1)
while (n>=1) {
k = pow(2, i)
while (n >= k) {
n = n - k
}
i--
}
在内部没有变化。很容易推断出它执行的次数m
,最后是c
的值:
这是“ C语言”中Modulus operator %
的确切定义:
n
请注意,由于while (n>=1) {
k = pow(2, i)
n = n % k // time complexity O(n / k) here instead of O(1)
i--
}
的连续值仅相差2倍,因此k
的值绝不会大于或等于n
;这意味着内部循环每个外部循环最多执行一次 。因此,外部循环最多执行 2k
次。
第一个和第二个循环都是
i
,这意味着总时间复杂度是O(log n)
。
更新:以前的Java数值测试。
O(log n) = O(log [a/b])
针对function T(n)
{
let t = 0;
let m = 1;
while (n > m) {
m *= 2; t++;
}
while (n >= 1) {
while (n >= m) {
n -= m; t++;
}
m/=2;
}
return t;
}
绘制T(n)
会显示一条不错的直线:
编辑:对代码段 2)的更详尽的解释。
在代码段 1)的末尾,log(n)
的值表示整数{{1}的二进制表示形式中有效位的数量 }。
计算具有正2的幂i = ceil(log2(n))
的整数的模量等效于舍弃,除前ceil(n)
位之外的所有位。例如:
2^i
摘要 2)的操作等效于一次删除i
的最高有效位,直到只剩下零。例如:
n = ...00011111111 (binary)
m = ...00000100000 (= 2^5)
n % m = ...00000011111
----- (5 least significant bits)
当前最高有效位(由n
指向)是:
outer loop no | n
----------------------------
1 | ...110101101
| ^
2 | ...010101101
| ^
3 | ...000101101
| ^
4 | ...000001101
| ^
: | :
: | :
i (=9) | ...000000001
| ^
----------------------------
final | 000000000
的值已经小于^
(等于位位置值),所以内部循环不会执行 n
)。k = 2^i
大于^
但小于n
(对应当前位置k
上方的位。因此,当2k
的所有有效位均为1时,将出现“最坏”情况。在这种情况下,内部循环始终执行一次。
无论如何,对于^
的任何值,外循环执行n
次。