在这个特定的代码中推理二次复杂性

时间:2015-11-17 10:31:43

标签: python complexity-theory

我要求参考这段代码:

array = [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41]
print sum(i for i in array if array.index(i) % 2 == 0)*array[-1] if array != [] else 0

你可以在这里看到:Python code for sum with condition
这是Quadratic,因为 for 循环后跟一个 if 语句,在括号内?

这个代码是由另一个人在同一页面上提出的 - array[-1] * sum(array[::2])没有二次行为吗?  我认为,它又是一个二次方,因为它必须进行遍历,而且也是一个替代的遍历。

提前致谢。

2 个答案:

答案 0 :(得分:1)

是的,array.index使它成为二次方。

让我们先把所有不相关的东西切掉。条件是因为复杂性推理无关紧要(我们将array != []并且该检查需要O(1)次。与array[-1]相乘也是如此。所以你离开了:

sum(i for i in array if array.index(i) % 2 == 0)

现在内部是一个生成器,它将扩展为一个循环遍历array的匿名函数,并产生一堆值,每次迭代最多一次。 sum函数接收这些值并将它们相加。

令人困惑的事情可能是发电机实际上是如何工作的。它实际上是通过运行与消费者的代码混合的生成器来工作的。这导致复杂性是生成器和消费者的复杂性的总和(即sum)。现在sum具有线性复杂性(它应该具有,如果我写它的话)。

因此对于生成器,它遍历数组,但是对于数组中的每个元素,它调用array.index,其复杂度为O(N)

要解决此问题,您可以使用enumerate来避免调用array.index(i),因为array.index(i)返回元素的第一个索引,它可能会或可能不会是您想要执行的操作是i,可能不是您实际找到的索引i

sum(i for idx, i in enumerate(array) if idx % 2 == 0)

要查看差异,请考虑列表array = [0, 1, 2, 2],第一个解决方案应该将此归结为4 array.index(2) == 2,因此它还会添加第二个2。然而,后面的解决方案将累加到2,因为enumerate将枚举array中的元素,产生对(0,0)(1,1)(2,2)(3,2) - 其中第一个组件是实际索引,而第二个组件是实际元素。这里省略了第二个2,因为它实际上来自索引3

答案 1 :(得分:0)

第一个解决方案确实是二次方的:当你调用array.index时,你基本上每次都会在array上进行迭代,所以它的行为就像一个嵌入式循环。

第二个解决方案只遍历列表一次,跳过每个奇数索引。