枚举的复杂性

Posted

技术标签:

【中文标题】枚举的复杂性【英文标题】:Complexity of enumerate 【发布时间】:2015-09-16 14:52:17 【问题描述】:

我看到很多关于python内置方法的运行时复杂度的问题,并且很多方法都有很多答案(例如https://wiki.python.org/moin/TimeComplexity、https://www.ics.uci.edu/~pattis/ICS-33/lectures/complexitypython.txt、Cost of len() function等。 )

我没有看到任何地址枚举。我知道它至少返回一个新数组(索引),但生成它需要多长时间,另一个数组是否只是原始数组?

换句话说,我假设它是 O(n) 用于创建一个新数组(迭代)和 O(1) 用于重用原始数组......总共 O(n) (我认为)。副本的另一个 O(n) 是 O(n^2),还是其他什么...?

【问题讨论】:

O(n^2) 意味着 O(n * n) 不是 O(n + n) enumerate 返回一个枚举对象——它是一个迭代器对象——而不是一个列表,所以它的复杂性在一定程度上取决于它的使用方式。 没有list.enumerate。 built-in enumerate() function 可用于任意迭代。 【参考方案1】:

枚举函数返回一个迭代器。 here 描述了迭代器的概念。

基本上这意味着迭代器被初始化指向列表的第一项,然后每次调用其 next() 方法时返回列表的下一个元素。

所以复杂度应该是:

初始化:O(1)

返回下一个元素:O(1)

返回所有元素:n * O(1)

请注意 enumerate 不会创建新的数据结构(元组列表或类似的东西)!它只是迭代现有列表,牢记元素索引。

您可以自己尝试一下:

# First, create a list containing a lot of entries:
# (O(n) - executing this line should take some noticeable time)
a = [str(i) for i in range(10000000)] # a = ["0", "1", ..., "9999999"]

# Then call the enumeration function for a.
# (O(1) - executes very fast because that's just the initialization of the iterator.)
b = enumeration(a)

# use the iterator
# (O(n) - retrieving the next element is O(1) and there are n elements in the list.)
for i in b:
    pass  # do nothing

【讨论】:

【参考方案2】:

假设天真的方法(枚举复制数组,然后迭代它),你有 O(n) 时间来复制数组,然后 O(n) 时间来迭代它。如果这只是 n 而不是 O(n),那么您总共将有 2 * n 时间,但这不是 O(n) 的工作方式;你所知道的是,它所花费的时间将是 一些 n 的倍数。无论如何,这(基本上)是 O(n) 的意思,所以无论如何,枚举函数都是 O(n) 时间。

【讨论】:

就像@caenyon 的例子一样,考虑到人们经常使用枚举,我假设像for i,v in enumerate(a) 这样的情况是O(n+n+1),因此是O(2n)? @10'004 否。在算法复杂性中的主导项是线性的任何情况下(即,如果算法所花费的时间是 n 的某个倍数),复杂度为 O(n)。无论实际时间是2n、3n、4n、0.5n,还是n的任意倍数,复杂度总是O(n)。 @10'004: enumerate() 可能与无限生成器一起使用,因此它不会复制其输入。虽然它不会改变时间复杂度,即使它改变了(对于有限的输入)。【参考方案3】:

正如 martineau 所指出的,enumerate() 不会复制数组。相反,它返回一个用于迭代数组的对象。对enumerate() 本身的调用是 O(1)。

【讨论】:

以上是关于枚举的复杂性的主要内容,如果未能解决你的问题,请参考以下文章

Scala 定义复杂枚举

复杂的变量类型:枚举结构数组(例子)

打字稿泛型中的自定义枚举过于复杂

poj 2888 Magic Bracelet

PAT1049-----枚举法,找规律题,注意降低时间复杂度

迭代器