“前K个最频繁的元素”的最差的运行时复杂度分析

时间:2018-10-26 01:17:39

标签: python algorithm time-complexity

问题描述:

  

给出一个非空的单词列表,返回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)。

以上内容是否是正确的直观分析?

1 个答案:

答案 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个元素...