问题描述:
给出一个非空的单词列表,返回k个最频繁的元素。
您的答案应按频率从高到低的顺序排序。如果 两个词具有相同的频率,则词的频率较低 字母顺序优先。
例如:示例1:输入:[“ i”,“ love”,“ stackoverflow”,“ i”,“ love”, “ coding”],k = 2输出:[“ i”,“ love”]说明:“ i”和“ love”是 两个最常用的词。请注意,由于 字母顺序较低。
我的使用频率段的Python解决方案:
def topKFrequent(words, k):
wordCount = collections.Counter(words)
freq = [[] for i in range(len(words) + 1)]
res = []
for word, count in wordCount.items():
freq[count].append(word)
for i in range(len(freq) - 1, 0, -1):
if k == 0:
break
elif k >= len(freq[i]):
res.extend(sorted(freq[i]))
k -= len(freq[i])
else:
res.extend(sorted(freq[i])[:k])
break
return res
现在,我的争论是上面的代码在O(nlogn)中运行,而忽略了分别为O(n)的Counter初始化和freq初始化,最终循环在最坏的情况下将只有一个存储桶,其中的所有单词(每个单词只出现一次),所以我们最终只是对那个存储桶进行了排序,即nlog(n)。
以上内容是否是正确的直观分析?
答案 0 :(得分:0)
是的,您的分析是正确的。如果您有n
个单词,那么您的初始化步骤将在O(n)
中运行。然后,您的for循环会对每个O(m log m)
分区进行j
排序。这是一个证明:
让 L 为 n 个元素的列表。将 L 分区为 j 个不同的分区,每个分区包含 n_1,...,n_j 个元素。显然 n_1 + ... + n_j = n 和 1 <= j <= n 。
我们可以忽略不处理任何项目的迭代,因为它们受恒定的 n 操作限制。因此,for循环确实适用于 j 个迭代,并且每个循环均适用 O(n_i log n_i)。因此,对于适当的常量 C_i ,这些迭代中的每一个都由 C_i n_i log n_i 限制。这样,总工作量为 C_1 n_1 log n_1 + ... + C_j n_j log n_j 。假设 K 是 C_i 中最大的。然后,这由 K n_1 log n + ... + K n_j log n = K(n_1 + ... + n_j)log n = K n log n 界定。因此,循环在 O(n log n)时间内运行。
我会注意到,有一种n log k
算法涉及使用最小堆,其中最多保留k
个元素...