说,我希望计算两个列表C = A - B
的差异:
A = [1,2,3,4,5,6,7,8,9]
B = [1,3,5,8,9]
C = [2,4,6,7] #Result
A
和B
都使用唯一的整数进行排序(不确定是否有办法告诉Python有关列表的此属性)。我需要保留元素的顺序。 AFAIK有两种可行的方法
方法1 :将B转换为集合并使用列表解析来生成C:
s = set(B)
C = [x for x in A if x not in s]
方法2 :直接使用列表理解:
C = [x for x in A if x not in B]
为什么#1
比#2
效率更高?是否有转换为集合的开销?我在这里缺少什么?
更新:我知道设置的平均O(1)
查询时间比列表的O(n)
快,但如果原始列表A
包含有关百万左右的整数,集合创作实际上不会花费更长时间吗?
答案 0 :(得分:12)
将列表转换为集合会产生开销,但是一个集合基本比那些in
测试的列表更快。
您可以立即查看项目x
是否在y
集中,因为下面使用的是哈希表。无论你的集合有多大,查找时间都是相同的(基本上是瞬时的) - 这在Big-O表示法中称为O(1)。对于列表,您必须单独检查每个元素,以查看项x
是否在列表z
中。随着列表的增长,检查将花费更长的时间 - 这是O(n),这意味着操作的长度与列表的长度直接相关。
增加的速度可以抵消设置的创建开销,这就是设置检查最终更快的方式。
编辑:要回答其他问题,Python无法确定您的列表是否已排序 - 无论如何您都使用标准list
对象。因此,它不能通过列表理解来实现O(log n)性能。如果你想编写自己的二进制搜索方法,假设列表已经排序,你当然可以这样做,但O(1)任何一天都会击败O(log n)。
答案 1 :(得分:7)
集合中查找(x中的S)的平均时间复杂度为O(1),而列表的相同时间为O(n)。
查看详细信息答案 2 :(得分:6)
根据Python documentation on time complexity
x in s
是平均线性时间操作,或O(n)
。x in s
平均为常量时间操作,或O(1)
。构建集合是最坏情况的线性时间操作,因为需要扫描列表中的所有元素以构建散列表,因此O(n)
。 n
是集合中元素的数量。
关键的观察是,在方法1 中,构建一个集合,s = set(B)
只是一次性操作,之后我们只有n
总数如x not in B
中所述的集合成员资格测试,总计O(n) + n * O(1)
或O(n)
时间复杂度。
在方法2 中,对x not in B
中的每个元素执行列表成员资格测试A
,因此总时间复杂度为n * O(n) = O(n^2)
。< / p>