我遇到了一个问题,要求在下面的代码中描述Big O中的计算复杂性:
i = 1;
while(i < N) {
i = i * 2;
}
我发现this Stack Overflow问题要求答案,最多的答案说它是Log2(N)。
首先想到答案看起来是正确的,但我记得学习了伪多项式运算时,以及计算复杂度如何衡量输入长度的难度,而不是值。
因此,对于整数输入,复杂性应该是输入中的位数。
因此,这个函数不应该是O(N)吗?因为循环的每次迭代都会将i中的位数增加1,直到它达到与N相同的位。
答案 0 :(得分:0)
这取决于重要的问题:&#34;乘法常数运算&#34;?
在现实世界中,它通常被认为是常量,因为你有固定的32位或64位数,并且它们相乘总是相同(=恒定)的时间。 另一方面 - 你有限制N&lt; 32/64位(或任何其他如果使用它)。
理论上你不考虑乘法作为常数运算,或者对于一些特殊的算法,其中N可以增长太多而无法忽略乘法复杂性,你是对的,你必须开始考虑乘法的复杂性。
乘以常数(在这种情况下为2)的复杂性 - 每次都必须经过每一位,并且你有log_2(N)
位。
在到达log_2(N)
N
次
以log_2(N) * log_2(N) = O(log_2^2(N))
PS:Akash有一个好处,即乘以2可以写为常量运算,因为二进制中唯一需要的是&#34;加零&#34; (类似于在&#34中乘以10;人类可读&#34;格式,你只需加零4333 * 10 = 43330)
然而,如果乘法不那么简单(你必须经历所有位),那么前面的答案是正确的
答案 1 :(得分:0)
此代码可能在以下功能中找到:
function FindNextPowerOfTwo(N) {
i = 1;
while(i < N) {
i = i * 2;
}
return i;
}
这里,输入可以被认为是k
位无符号整数,我们可以将其想象为具有k
位的字符串。因此输入大小为k = floor(log(N)) + 1
位输入。
赋值i = 1
应解释为创建一个新的位串并为其分配长度为一位的字符串1
。这是一个恒定的时间操作。
循环条件i < N
比较两个位串以查看哪个代表较大的数字。如果智能地实现,这将花费时间与两个位串中较短的长度成比例,其总是i
。正如我们将看到的,i
位串的长度从1开始并增加1,直到它大于或等于N
位串的长度,k
。当N
不是2的幂时,i
位字符串的长度将达到k + 1
。因此,在最坏的情况下,评估条件所花费的时间与1 + 2 + ... + (k + 1) = (k + 1)(k + 2)/2 = O(k^2)
成正比。
在循环中,我们将i
一遍又一遍地乘以2。此操作的复杂性取决于如何解释乘法。当然,有可能以这样一种方式表示我们的位串,即我们可以通过执行位移并在末尾插入零来智能地乘以2。这可以做成恒定时间操作。如果我们没有注意到此优化并执行标准长乘法,我们会扫描i
的位字符串一次以写出一行0
并再次写出i
使用额外的0
,然后我们通过扫描这两个字符串来执行常规添加。这里每个步骤所花费的时间与i
位串的长度(实际上,加上一个)成比例,因此整个事件与i
的比例成正比。位串长度。由于i
的位串长度为1, 2, ..., (k + 1)
,因此总时间为2 + 3 + ... + (k + 2) = (k + 2)(k + 3)/2 = O(k^2)
。
返回i
是一个恒定时间操作。
将所有内容放在一起,运行时间由c * k ^ 2形式的函数从上方和下方限定,因此最坏情况复杂性的约束为Theta(k^2) = Theta(log(n)^2)
。
答案 2 :(得分:-1)
在给定的示例中,您没有将i的值增加1,而是每次都将它增加一倍,因此它朝N移动速度快2倍。通过将它乘以2可以减小搜索空间的大小(我到N之间的一半;即,将输入空间减少2倍。因此,程序的复杂性为 - log_2(N)。
如果你偶然发生了 -
i = i * 3;
程序的复杂程度为log_3(N)。