Python哈希表实现为何比列表迭代更高效?基于赎金信问题分析
这是来自HackerRank的赎金信问题。你自己的实现通过了大部分测试,但在大规模数据场景下超时,而基于哈希表的实现却能瞬间通过所有测试。我们来拆解两者的效率差异:
你的实现
m, n = map(int, input().strip().split(' ')) magazine = input().strip().split(' ') ransom = input().strip().split(' ') yesNo = "Yes" for i in ransom: if(ransom.count(i) > magazine.count(i)): yesNo = "No" print(yesNo)
更高效的哈希表实现
def ransom_note(magazine, ransom): rc = {} # dict of word: count of that word in the note for word in ransom: if word not in rc: rc[word] = 0 rc[word] += 1 for word in magazine: if word in rc: rc[word] -= 1 if rc[word] == 0: del rc[word] if not rc: return True return False m, n = map(int, input().strip().split(' ')) magazine = input().strip().split(' ') ransom = input().strip().split(' ') answer = ransom_note(magazine, ransom) if(answer): print("Yes") else: print("No")
为什么哈希表实现效率更高?
这问题的核心在于时间复杂度的量级差异——你的列表迭代实现是O(n*(n+m))的时间复杂度,而哈希表版本是O(n+m),当数据规模变大时,后者的效率会呈指数级领先。
你的实现的性能瓶颈
你的代码里,每次循环都调用了ransom.count(i)和magazine.count(i):
count()方法的本质是遍历整个列表来统计目标元素的出现次数,每次调用的时间复杂度是O(k)(k是列表长度)。- 假设ransom有n个元素,magazine有m个元素,那么你的代码总时间开销是O(n*(n+m)):每个ransom元素都要触发两次全列表遍历。
- 举个直观的例子:如果ransom有1000个元素,magazine有10000个元素,你的代码要执行1000*(1000+10000)=11,000,000次遍历操作,这在大规模数据下会直接导致超时。
哈希表实现的效率优势
哈希表(Python里的字典)的查找、插入、删除操作平均时间复杂度都是O(1),这是它能高效解决问题的关键:
- 统计赎金信单词次数:遍历ransom列表一次,用字典记录每个单词的出现次数,这一步是O(n)的时间——每个单词只处理一次,字典的增/改操作都是O(1)。
- 抵消杂志中的单词:遍历magazine列表一次,遇到字典里存在的单词就把计数减一,当计数减到0时删除该键,这一步是O(m)的时间——同样每个单词只处理一次,字典的查/改/删操作都是O(1)。
- 提前终止优化:遍历magazine的过程中,一旦字典被清空(所有赎金单词都已满足数量要求),可以直接返回
True,不需要遍历完整个杂志列表,进一步节省时间。
- 还是用之前的例子,哈希表版本的总操作次数最多是1000+10000=11,000次,比你的实现少了1000倍的工作量,速度自然快得惊人。
额外的细节对比
- 当ransom里有大量重复单词时,你的代码会重复调用
count()做无意义的重复统计,而哈希表只需要统计一次,差距会更明显。 - 哈希表的查找是直接通过哈希值定位,不需要像列表那样逐个元素比对,这也是它能做到O(1)查找的核心原因。
内容的提问来源于stack exchange,提问作者Michael Cavallaro
相关产品推荐
相关产品推荐

