具有lambda函数的filter()的复杂性分析

Tom*_*tor 3 python functional-programming time-complexity

给出两个列表,list1list2

list3 = filter(lambda x: x in list1,list2)
Run Code Online (Sandbox Code Playgroud)

这将返回两个列表的交集.

如何找到此算法的复杂性?我发现时间复杂度x in list1O(n),其中n是列表中元素的数量,但是如何filter

Ant*_*ala 8

您的代码执行O(len(list1) * len(list2))元素的比较操作.

  • 您的lambda函数执行O(len(list2))次数,每个元素被过滤一次.请参阅filterPython 3(Python 2)中的文档:

    filter(function, iterable)

    iterator函数返回true的那些元素iterable构造一个.iterable可以是序列,支持迭代的容器,也可以是迭代器

    (强调我的)

    显然,对于iterable中的每个(不同)元素,函数被调用至少一次 - 知道什么时候不需要调用它也意味着在一般情况下也解决Halting问题,甚至Python核心开发人员还没有解决;-) .在CPython的3实践中filter内置创建一个迭代其中当推进,在迭代顺序的每个元素(不同或不)执行一次函数.

  • 如记录所述x in list1,O(len(list1))在平均和最差情况下进行比较.


为了加快速度,请使用set; 你根本不需要lambda函数(使用__contains__魔法)

list3 = filter(set(list1).__contains__, list2)
Run Code Online (Sandbox Code Playgroud)

这将构建一个setlist1曾经在O(len(list1))时间和运行过滤反对与O(len(list2))平均水平的复杂性O(len(list1) + len(list2))


如果元素的排序list2 无关紧要,那么你也可以这样做

set(list1).intersection(list2)
Run Code Online (Sandbox Code Playgroud)

应该具有比filter上述更低的常数; 对于真正快速的代码,您应该对列表进行排序,以便将较小的代码转换为集合(因为交集和集合构建都记录了平均复杂度O(n),但是由于调整大小set,集合构建最可能会有更大的常量,因此它将有意义的是从较小的构建集合以减少这些常量的权重):

smaller, larger = sorted([list1, list2], key=len)
result = set(smaller).intersection(larger)
Run Code Online (Sandbox Code Playgroud)

请注意,Python 2和3彼此不同.filter在Python 3中返回一个生成器,实际运行时间取决于生成的生成器消耗的元素数量,而在Python 2中,将预先生成一个列表,如果只需要第一个值,这可能会更昂贵.