查找特定python算法的时间复杂度

时间:2013-11-11 21:18:58

标签: python time-complexity

您好我需要了解以下算法的时间复杂度。

def complex(n):
    l=[]
    i=1
    while i<n:
        l=list(range(i))
        i*=2

我已经意识到它在循环中运行int(log(n,2))次,但我很难将范围(i)合并到最终表达式中。 任何帮助表示感谢。

2 个答案:

答案 0 :(得分:3)

您已经知道它运行int(log(n, 2))次迭代。 (您可以通过在循环中添加一个计数器并使用例如1,2,4,8,16,32,64等调用它来非常轻松地进行测试,并且每次都看到计数器上升1 n加倍。)

现在你想知道循环内部需要多长时间。在这里,您需要知道rangelist函数的时间复杂度。我可以给你那些答案,事实上你可能会猜到它们,但除非你开始阅读CPython的源代码,否则你无法真正证明。所以,让我们用一些简单的时间进行测试:

import timeit
for i in range(20):
    n = 1 << i
    t = timeit.timeit(lambda: list(range(n))
    print('{} takes {}'.format(n, t))

如果你运行它,你会看到,一旦你超过32,加倍n似乎加倍了它所需的时间。那么,这意味着list(range(n))是O(n),对吗?

让我们验证一下是否合理。我不知道你是使用Python 2.x还是3.x,所以我会用两种方式解决。

在2.x中:range(n)必须计算n个整数,并构建一个列表n值。这似乎应该是O(n)。

在3.x中:range(n)只返回一个记住数字n的对象。那应该是O(1)。但是我们会在list上调用range,它必须迭代整个范围,计算所有n个整数,并构建长n个列的值。所以它仍然是O(n)。

将它放回到循环中,循环中有O(log n)次,每次O(i)复杂度。因此,总时间为O(1)+ O(2)+ O(4)+ O(...)+ O(n / 4)+ O(n / 2)+ O(n),其中log(n)总结中的步骤。换句话说,它是geometric sequence的总和。现在你可以解决问题了。 (或者,如果没有,你就会陷入一个新的角色,如果你自己无法解决这个问题,有人可以为你解决这个问题。)


你得出结论是-(1-2**log(n,2))。这不太对,因为你想要一个封闭的范围,而不是半开范围,所以它应该是-(1-2**log(n+1,2))。但这可能是我没有清楚地解释它的错,而且没关系太多,所以让我们首先考虑你的版本。

2**log(n, 2)显然是n。 (如果你不能很好地理解取幂和对数,你应该找到一个关于数学的教程,但同时你可以用各种不同的n值来测试它,以说服自己。)

同时,任何-(1-x)的{​​{1}}只是x

所以,总和只是x-1

如果您返回并使用正确的n-1代替log(n+1, 2),则会获得log(n, 2)

那么,这是正确的吗?让我们测试一些实际数字。

如果2n-1,您获得n = 16。如果1+2+4+8+16 = 31 = 2n-1,则获得n = 1024。你投掷的任何2的幂,你得到了正确的答案。对于非幂2,如1000,你会得到1+2+4+…+256+512+1024 = 2047 = 2n-1,这不完全是1+2+4+…+256+512+1000 = 2023,但它总是在2的因子内。(事实上,它是2n-1 ,或n + 2**(ceil(log(n, 2)) - 1其中n + m - 1m的四舍五入为2的幂。)

无论如何,nn-12n-1 ......这些都是n + 2**(ceil(log(n, 2)) - 1

你可以通过使用O(n)的不同值对整个函数进行计时来回过头来测试这一点,并且看到,除了非常小的数字,当你加倍n它需要大约两倍的时间。< / p>

答案 1 :(得分:0)

这个比它看起来更棘手,因为list(range(i))基于i,它在几何上增长。但是,有一种简单的方法来查看问题。相对于n,总共创建了多少个元素?您可以通过假设n的方便值(即2的幂)来简化问题。

如果你仍然陷入困境,那就从小处开始吧。如果n = 1,总共创建了多少个元素?然后看看你得到的答案是n = 2,n = 4,n = 8,依此类推。模式应该很快就会变得明显。

相关问题