Python 代码片段的大O,带“O”;在;列表上的操作
下面这段代码的最大优点是什么Python 代码片段的大O,带“O”;在;列表上的操作,python,time-complexity,big-o,Python,Time Complexity,Big O,下面这段代码的最大优点是什么 with open(file_name) as f: for word in f: w = word.rstrip() k = ''.join(sorted(w)).lower() if k in words: words[k].append(w) else: words[k] = [w] list中的x是O(n),但此代码未对列表执行成员资格测
with open(file_name) as f:
for word in f:
w = word.rstrip()
k = ''.join(sorted(w)).lower()
if k in words:
words[k].append(w)
else:
words[k] = [w]
list中的
x
是O(n)
,但此代码未对列表执行成员资格测试<代码>单词看起来像是一个dict
,在dict
的键(或集合中的中)中的成员资格测试是O(1)
(从技术上讲,最坏的情况可能是O(n)
,但这是平均情况O(1)
,他们甚至努力阻止故意造成碰撞的企图)
使用集合可以稍微简化此代码。但是defaultdict
,因此在查找不存在的键时,创建列表
s是隐式完成的:
import collections
words = collections.defaultdict(list)
with open(file_name) as f:
for word in f:
w = word.rstrip()
words[''.join(sorted(w)).lower()].append(w)
如果您想要唯一性(尽管它会失去顺序),只需更改为defaultdict(set)
,并将append
更改为add
。如果您需要唯一性和排序,collections.OrderedDict
可以(大部分)作为一个有序的集合使用:
import collections
words = collections.defaultdict(collections.OrderedDict)
with open(file_name) as f:
for word in f:
w = word.rstrip()
# True is placeholder, any value will do if you're using in tests properly
words[''.join(sorted(w)).lower()][w] = True
words
中的k将具有线性复杂度,即,如果words
是一个列表,则O(len(words))
看起来words
是一个dict
,但是,由于words[k]
显然是通过一个字符串对其进行索引,所以列表不会接受这一点
对于dict
,访问时间可视为常数O(1),用于搜索(中的)和更新。(这是摊销时间。)您的问题是什么?代码中有几个部分对时间复杂度有影响<例如,code>sorted()
在
@klauds中应该有远不止一个。我能肯定地说这不是O(N)吗?排序的平均复杂度应该是O(N logn)
。有关详细信息,请参阅。我认为所有的复杂性都是O(N)+O(N log N),所以它是O(N log N)单词
由字符串索引,它不能是列表。@JohnDoLittle:单词
绝对不是列表
。您正在使用一个str
在其中执行查找,如果它是一个列表
,您将得到重复的类型错误:列表索引必须是整数或片,而不是str
;它是一个list
s的dict
,或某种深奥(非内置)类型。由于您从未测试dict
(即list
s)的值中的成员资格,因此您从未支付任何O(n)
查找成本,感谢您解释整个片段?整个片段读取一个文件,因此时间将由I/O控制。如果您没有过长的单词,那么读取的字符数显然是线性的。算法上最慢的部分是调用sorted
,它是O(n*log(n)),其中n=len(w)
。如果你所有的单词都比整个文本短得多,那么它可以被认为是一个常数,整个片段就是O(文件长度)。如果您碰巧有一个由2或3个超长单词组成的文本,则性能将由排序的控制(对数线性),但这是一个边缘情况。让我们分解一下,读取文件中N行的复杂性是O(N),将排序的(w)与N-1进行比较的复杂性是O(N对数N)。因此,在我看来,主要的运算是排序的(w),也就是O(n logn),这取决于我们谈论的n是什么。整个过程是O(k*s),其中k是字符数(我们精确扫描每个字符一次),s是分析每个单词的复杂性(拆分为单词是每个字符O(1))。如果w=len(最长字)