设置函数转换列表的时间复杂度,反之亦然
Time complexity for function converting list to set and vice versa
我正在将列表转换为集合并返回列表。我知道 set(list)
需要 O(n) 时间,但我正在将它转换回同一行 list(set(list))
中的列表。由于这两个操作都需要 O(n) 时间,所以时间复杂度现在是 O(n^2) 吗?
逻辑 1:
final = list(set(list1)-set(list2))
逻辑 2:
s = set(list1)-set(list2)
final = list(s)
这两种实现是否具有不同的时间复杂度,如果有,哪一种更有效?
不需要进行一次集合转换,因为 set.difference
可以按应有的方式处理任何可迭代对象:
final = list(set(list1).difference(list2))
但是整个事情的渐近时间和space复杂度仍然是O(m+n)
(两个列表的大小)。
在这两个版本中你正在做的:
- 将列表转换为集合
- 将另一个列表转换为集合
- 减去两组
- 将结果集转换为列表
其中每一个都是 O(n),其中 n 是两个起始列表大小的界限。
那是四次 O(n),所以总的来说是 O(n)。
你的两个版本本质上是一样的。
您的两个版本相同,从 dis
:
>>> dis.dis("list(set(list1) - set(list2))")
1 0 LOAD_NAME 0 (list)
2 LOAD_NAME 1 (set)
4 LOAD_NAME 2 (list1)
6 CALL_FUNCTION 1
8 LOAD_NAME 1 (set)
10 LOAD_NAME 3 (list2)
12 CALL_FUNCTION 1
14 BINARY_SUBTRACT
16 CALL_FUNCTION 1
18 RETURN_VALUE
>>> dis.dis("s = set(list1) - set(list2);list(s)")
1 0 LOAD_NAME 0 (set)
2 LOAD_NAME 1 (list1)
4 CALL_FUNCTION 1
6 LOAD_NAME 0 (set)
8 LOAD_NAME 2 (list2)
10 CALL_FUNCTION 1
12 BINARY_SUBTRACT
14 STORE_NAME 3 (s)
16 LOAD_NAME 4 (list)
18 LOAD_NAME 3 (s)
20 CALL_FUNCTION 1
22 POP_TOP
24 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>>
这两者之间的唯一区别是第二个将它存储到一个变量s
,所以它必须LOAD_NAME
名称s
。在第一个代码中,list
首先被调用,但在第二个代码中,get 稍后被调用。
但是在@user2390182 的回答中,它加载的不是第二次加载 set
LOAD_NAME
,而是加载函数名称 difference
,IMO 在这里是最有效的:
>>> dis.dis("list(set(list1).difference(list2))")
1 0 LOAD_NAME 0 (list)
2 LOAD_NAME 1 (set)
4 LOAD_NAME 2 (list1)
6 CALL_FUNCTION 1
8 LOAD_METHOD 3 (difference)
10 LOAD_NAME 4 (list2)
12 CALL_METHOD 1
14 CALL_FUNCTION 1
16 RETURN_VALUE
>>>
我正在将列表转换为集合并返回列表。我知道 set(list)
需要 O(n) 时间,但我正在将它转换回同一行 list(set(list))
中的列表。由于这两个操作都需要 O(n) 时间,所以时间复杂度现在是 O(n^2) 吗?
逻辑 1:
final = list(set(list1)-set(list2))
逻辑 2:
s = set(list1)-set(list2)
final = list(s)
这两种实现是否具有不同的时间复杂度,如果有,哪一种更有效?
不需要进行一次集合转换,因为 set.difference
可以按应有的方式处理任何可迭代对象:
final = list(set(list1).difference(list2))
但是整个事情的渐近时间和space复杂度仍然是O(m+n)
(两个列表的大小)。
在这两个版本中你正在做的:
- 将列表转换为集合
- 将另一个列表转换为集合
- 减去两组
- 将结果集转换为列表
其中每一个都是 O(n),其中 n 是两个起始列表大小的界限。
那是四次 O(n),所以总的来说是 O(n)。
你的两个版本本质上是一样的。
您的两个版本相同,从 dis
:
>>> dis.dis("list(set(list1) - set(list2))")
1 0 LOAD_NAME 0 (list)
2 LOAD_NAME 1 (set)
4 LOAD_NAME 2 (list1)
6 CALL_FUNCTION 1
8 LOAD_NAME 1 (set)
10 LOAD_NAME 3 (list2)
12 CALL_FUNCTION 1
14 BINARY_SUBTRACT
16 CALL_FUNCTION 1
18 RETURN_VALUE
>>> dis.dis("s = set(list1) - set(list2);list(s)")
1 0 LOAD_NAME 0 (set)
2 LOAD_NAME 1 (list1)
4 CALL_FUNCTION 1
6 LOAD_NAME 0 (set)
8 LOAD_NAME 2 (list2)
10 CALL_FUNCTION 1
12 BINARY_SUBTRACT
14 STORE_NAME 3 (s)
16 LOAD_NAME 4 (list)
18 LOAD_NAME 3 (s)
20 CALL_FUNCTION 1
22 POP_TOP
24 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>>
这两者之间的唯一区别是第二个将它存储到一个变量s
,所以它必须LOAD_NAME
名称s
。在第一个代码中,list
首先被调用,但在第二个代码中,get 稍后被调用。
但是在@user2390182 的回答中,它加载的不是第二次加载 set
LOAD_NAME
,而是加载函数名称 difference
,IMO 在这里是最有效的:
>>> dis.dis("list(set(list1).difference(list2))")
1 0 LOAD_NAME 0 (list)
2 LOAD_NAME 1 (set)
4 LOAD_NAME 2 (list1)
6 CALL_FUNCTION 1
8 LOAD_METHOD 3 (difference)
10 LOAD_NAME 4 (list2)
12 CALL_METHOD 1
14 CALL_FUNCTION 1
16 RETURN_VALUE
>>>