刷题时,Python 中的 Counter
类是可以快速统计元素的频率,帮助解决各种涉及计数的问题。Counter
是 collections
模块中的一个类,本质上是一个字典,用于计数可哈希对象。
Counter
可以通过多种方式初始化:
from collections import Counter
# 从列表初始化
counter = Counter([1, 2, 2, 3, 3, 3])
print(counter) # 输出:Counter({3: 3, 2: 2, 1: 1})
counter = Counter("gallahad")
print(counter) # 输出:Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1})
counter = Counter({'red': 4, 'blue': 2})
print(counter) # 输出:Counter({'red': 4, 'blue': 2})
elements()
:返回一个迭代器,包含所有元素(重复元素会重复出现)。counter = Counter("gallahad")
for element in counter.elements():
print(element, end=" ") # 输出:g a l l a h a d
most_common([n])
:返回出现次数最多的前 n 个元素及其计数。如果不指定 n,则返回所有元素。counter = Counter("gallahad")
print(counter.most_common(2)) # 输出:[('a', 3), ('l', 2)]
update([iterable-or-mapping])
:增加计数。counter = Counter("gallahad")
counter.update("hello")
print(counter) # 输出:Counter({'a': 3, 'l': 3, 'h': 2, 'e': 1, 'o': 1, 'g': 1, 'd': 1})
subtract([iterable-or-mapping])
:减少计数。counter = Counter("gallahad")
counter.subtract("hello")
print(counter) # 输出:Counter({'a': 2, 'l': 1, 'g': 1, 'd': 1, 'h': -1, 'e': -1, 'o': -1})
from collections import Counter
s = "abracadabra"
counter = Counter(s)
print(counter) # 输出:Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
def is_anagram(s1, s2):
return Counter(s1) == Counter(s2)
print(is_anagram("listen", "silent")) # 输出:True
print(is_anagram("hello", "world")) # 输出:False
from collections import Counter
nums = [1, 2, 2, 3, 3, 3]
counter = Counter(nums)
print(counter) # 输出:Counter({3: 3, 2: 2, 1: 1})
def majority_element(nums):
counter = Counter(nums)
return counter.most_common(1)[0][0]
print(majority_element([3, 2, 3])) # 输出:3
from collections import Counter
def count_characters(s, k):
counter = Counter()
for i in range(k):
counter[s[i]] += 1
print(counter) # 输出窗口 [0, k) 内的字符频率
for i in range(k, len(s)):
counter[s[i]] += 1
counter[s[i - k]] -= 1
if counter[s[i - k]] == 0:
del counter[s[i - k]]
print(counter) # 输出每个窗口的字符频率
count_characters("abcabcbb", 3)
使用
Counter
计数窗口中字符频率,并滑动窗口更新计数。
代码逻辑
Counter
,统计窗口 [0, k)
内字符的频率Counter
s[i]
s[i - k]
s[i - k]
频率变成 0,则删除Counter
输入
count_characters("abcabcbb", 3)
初始窗口 [0,3) = "abc"
Counter({'a': 1, 'b': 1, 'c': 1})
窗口 [1,4) = "bca"
s[3] = 'a'
s[0] = 'a'
Counter({'b': 1, 'c': 1, 'a': 1}) # 变化不大,因为 'a' 重新进入
窗口 [2,5) = "cab"
s[4] = 'b'
s[1] = 'b'
Counter({'c': 1, 'a': 1, 'b': 1})
窗口 [3,6) = "abc"
s[5] = 'c'
s[2] = 'c'
Counter({'a': 1, 'b': 1, 'c': 1})
窗口 [4,7) = "bcb"
s[6] = 'b'
s[3] = 'a'
Counter({'b': 2, 'c': 1})
窗口 [5,8) = "cbb"
s[7] = 'b'
s[4] = 'b'
Counter({'b': 2, 'c': 1})
最终输出
Counter({'a': 1, 'b': 1, 'c': 1})
Counter({'b': 1, 'c': 1, 'a': 1})
Counter({'c': 1, 'a': 1, 'b': 1})
Counter({'a': 1, 'b': 1, 'c': 1})
Counter({'b': 2, 'c': 1})
Counter({'b': 2, 'c': 1})
def can_form(s1, s2):
counter1 = Counter(s1)
counter2 = Counter(s2)
for char, count in counter1.items():
if counter2[char] < count:
return False
return True
print(can_form("abc", "aabbcc")) # 输出:True
print(can_form("abc", "ab")) # 输出:False
from collections import Counter
s = "abracadabra"
counter = Counter(s)
most_common = counter.most_common(1)[0]
print(most_common) # 输出:('a', 5)
题目要求找出数组中出现次数最多的前 K 个元素。
from collections import Counter
import heapq
def topKFrequent(nums, k):
counter = Counter(nums)
return heapq.nlargest(k, counter.keys(), key=counter.get)
print(topKFrequent([1, 1, 1, 2, 2, 3], 2)) # 输出:[1, 2]
heapq.nlargest
函数从可迭代对象 iterable
中找出最大的 k
个元素,并返回一个列表。key
参数是一个函数,用于指定排序的依据。
在这个例子中:
k
是需要返回的最大元素的数量。counter.keys()
是可迭代对象,包含所有元素。key=counter.get
表示按照每个元素在 Counter
中的出现次数进行排序。最终,heapq.nlargest(k, counter.keys(), key=counter.get)
会返回出现次数最多的前 k
个元素。
题目要求将字符串数组中的字母异位词分组。
from collections import Counter, defaultdict
def groupAnagrams(strs):
anagrams = defaultdict(list)
for s in strs:
count = tuple(sorted(Counter(s).items()))
anagrams[count].append(s)
return list(anagrams.values())
print(groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"]))
# 输出:[['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]
使用 哈希表(defaultdict)+ 计数法(Counter) 来分组字母异位词(Anagrams)
defaultdict(list)
存储分组结果strs
s
中每个字符的频率(使用 Counter(s)
)(字符, 频率)
进行排序并转换为 tuple
(作为 dict
的 key)s
存入 anagrams
的相应组中anagrams.values()
转换为列表groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"])
单词 | Counter(s) |
排序后的 tuple |
分组结果 |
---|---|---|---|
"eat" |
{'e': 1, 'a': 1, 't': 1} |
(('a', 1), ('e', 1), ('t', 1)) |
[['eat']] |
"tea" |
{'t': 1, 'e': 1, 'a': 1} |
(('a', 1), ('e', 1), ('t', 1)) |
[['eat', 'tea']] |
"tan" |
{'t': 1, 'a': 1, 'n': 1} |
(('a', 1), ('n', 1), ('t', 1)) |
[['eat', 'tea'], ['tan']] |
"ate" |
{'a': 1, 't': 1, 'e': 1} |
(('a', 1), ('e', 1), ('t', 1)) |
[['eat', 'tea', 'ate'], ['tan']] |
"nat" |
{'n': 1, 'a': 1, 't': 1} |
(('a', 1), ('n', 1), ('t', 1)) |
[['eat', 'tea', 'ate'], ['tan', 'nat']] |
"bat" |
{'b': 1, 'a': 1, 't': 1} |
(('a', 1), ('b', 1), ('t', 1)) |
[['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']] |
最终 anagrams
的值:
[['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]
Counter
可以快速解决各种涉及计数的问题。它提供了高效的统计功能和丰富的内置方法,能够快速实现算法逻辑,减少代码量。