我在算法设计中有一个关于复杂性的问题。在这个问题中给出了一段代码,我应该计算这段代码的复杂性。 伪代码是:
for(i=1;i<=n;i++){
j=i
do{
k=j;
j = j / 2;
}while(k is even);
}
我为一些数字尝试了这个算法。我得到了不同的结果。例如,如果n = 6,则此算法输出如下所示
i = 1 -> executes 1 time
i = 2 -> executes 2 times
i = 3 -> executes 1 time
i = 4 -> executes 3 times
i = 5 -> executes 1 time
i = 6 -> executes 2 times
它没有常规主题,我该如何计算?
答案 0 :(得分:99)
其他答案给出的上限实际上太高了。该算法具有O(n)运行时,其上限比O(n * logn)更严格。
证明:让我们计算内循环将执行的总迭代次数。
外循环运行n
次。内部循环至少运行一次。
i
,内循环运行至少两次。这种情况发生n/2
次。i
,内循环至少运行三次。这种情况发生n/4
次。i
,内循环至少运行四次。这种情况发生n/8
次。因此内循环运行的总次数为:
n + n/2 + n/4 + n/8 + n/16 + ... <= 2n
内循环迭代的总量在n
和2n
之间,即它是Θ(n)。
答案 1 :(得分:6)
你总是假设你在每个级别都遇到了最糟糕的情况。
现在,你迭代一个包含N个元素的数组,所以我们先从O(N)
开始
现在假设你的i
总是等于X
而X
总是均匀(记住,每次都是最坏的情况)。你需要划分多少次{{1通过X
获取2
? (当偶数达到1时,这是偶数停止除法的唯一条件。)
换句话说,我们需要解决这个问题
1
X/2^k = 1
和X=2^k
k=log<2>(X)
这使我们的算法采用O(n log<2>(X))
步骤,可以很容易地写成O(nlog(n))
答案 2 :(得分:4)
对于这样的循环,我们不能分离内循环和外循环的计数 - &gt;变量被收紧了!
因此,我们必须统计所有步骤。
事实上,对于外循环的每次迭代(在angular.module('appName')
.service('GetDataService', function($http, $q WebServiceURL) {
this.getData = function(ServiceParameter) {
var defer = $q.defer();
$http.get(WebServiceURL + ServiceParameter)
.then(function(res){
defer.resolve(res.data);
}, function (err) { defer.reject(err)});
return defer.promise;
};
上),我们将有
i
其中1 + v_2(i) steps
是2-adic估值(例如参见:http://planetmath.org/padicvaluation),其对应于v_2
的素因子分解中2
的幂。
因此,如果我们为所有i
添加步骤,我们会得到以下步骤的总数:
i
然后我们看到步数 完全 :
n_steps = \sum_{i=1}^{n} (1 + v_2(i))
= n + v_2(n!) // since v_2(i) + v_2(j) = v_2(i*j)
= 2n - s_2(n) // from Legendre formula (see http://en.wikipedia.org/wiki/Legendre%27s_formula with `p = 2`)
由于n_steps = 2n - s_2(n)
是基数s_2(n)
中n
的数字之和,因此可以忽略不计(最多2
,因为基数log_2(n)
中的数字是与2
相比,0或1以及最多log_2(n)
个数字。
因此,算法的复杂性等同于n
:
n
不 许多其他解决方案中陈述的n_steps = O(n)
,但数量较少!
答案 3 :(得分:0)
让我们从最坏的情况开始:
如果你继续除以2(积分),你不需要停下来直到你
得到1.基本上使步数取决于位宽,
你发现使用两个对数的东西。所以内部是log n。
外部显然是n,所以总共N log N
。
答案 4 :(得分:0)
do
循环将j
减半,直到k
变为奇数。 k
最初是j
的副本,是i
的副本,因此do
运行1 {+ {1}}的权力,其中2
除以:
i
循环,这最多可以执行1 + log(i)do
次(以2为基数的对数)。
do
循环从{1}到for
迭代i
,因此上限为n
次(1 + log n),即O(n log n) )。