考虑以下代码:
def count_7(lst):
if len(lst) == 1:
if lst[0] == 7:
return 1
else:
return 0
return count_7(lst[:len(lst)//2]) + count_7(lst[len(lst)//2:])
注意:切片操作将被视为O(1)。
所以,我的语言告诉我它是O(n * logn),但我正在努力证明它是科学的。
很高兴能帮忙!
答案 0 :(得分:3)
好的,数学上(有点像)我得到这样的东西:
T(n) = 2T(n/2) + c
T(1) = 1
推广等式:
T(n) = 2^k * T(n/2^k) + (2^k - 1) * c
T(1) = 1
n/2^k == 1
时{p> k == logN
:
T(n) = 2^logN * T(1) + (2^logN - 1) * c
从T(1) = 1
开始并应用对数属性
T(n) = n * 1 + (n-1) * c
T(n) = n + n * c
T(n) = n * (1+c)
T(n) = O(n)
这不是O(n*logn)
的线索是您不必将两个子问题组合在一起。与mergesort
不同,您需要将两个子数组合并,此算法不必对递归结果执行任何操作,因此其时间可以表示为常量c
。
更新:背后的直觉
此算法应为O(n),因为只访问数组中的每个元素。它可能看起来并不简单,因为递归永远不会。
例如,您将问题分成两个子问题的一半大小,然后将每个子问题分成一半大小并继续进行,直到每个子问题的大小为1. 当你完成时,你将会有n个子问题,大小为1,n*O(1) = O(n)
。
从第一个问题开始到大小为1的N个问题的路径是对数的,因为在每个步骤中,您将细分为两个。但是在每个步骤中,您都不会对结果做任何事情,因此这不会给解决方案增加任何时间复杂性。
希望这有帮助
答案 1 :(得分:2)
最简单的方法是假设n是2的倍数,以简化:n = 2m
算法的时间复杂度是(c是常数):
t(n) = 2 t(n/2) + c
使用递归得到:
t(n) = 22 t(n/22) + 2c + c
...
= 2log(n) t(n/2log(n)) + c(2log(n)-1 + ... + 22 + 21 + 20)
可以通过注意log(n) = m
,从而2log(n) = 2m = n
来简化。
= n + c(2log(n)-1 + ... + 22 + 21 + 20)
最后,上面的总和可以减少到2log(n)
(等于n
)
t(n) = (1 + c) n
所以你的解决方案是O(n)
答案 2 :(得分:1)
您扫描列表的所有元素,即O(n)。与简单递归扫描的唯一区别 是您扫描它们的顺序。你做1,n / 2,2,3 / 4n等......而不是1,2,3 ....但复杂性是相同的。