代码之家  ›  专栏  ›  技术社区  ›  user1008636

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

  •  0
  • user1008636  · 技术社区  · 6 年前

    问题描述:

    给定一个非空的单词列表,返回k最频繁的元素。

    你的答案应该按频率从高到低排序。如果 两个词有相同的频率,然后是较低频率的词 按字母顺序排列。

    例如:例1:输入:[“i”,“love”,“stackoverflow”,“i”,“love”, “编码”],k=2输出:【I”,“爱”】解释:“I”和“爱”是 两个最常见的词。注意“我”在“爱”之前是因为 较低的字母顺序。

    使用频率桶的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)中,忽略了计数器初始化和freq初始化,每个都是o(n),在最坏的情况下,最后一个循环将有一个包含所有单词的bucket(每个单词恰好出现一次),所以我们最终只对该bucket进行排序。,即nlog(n)。

    以上是正确的直观分析吗?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Alex Reinking    6 年前

    是的,你的分析是正确的。如果你有 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日志n_i) 工作。因此,每个迭代都有 登录 对于合适的常数 CII . 总的工作量是 C_1 n_1日志n_1+…+日志 . 假设 K 是最大的 CII . 那么这是由 k n_1日志n+…+k n_j log n=k(n_1+……+n_j)logn=k n logn . 因此,循环运行 O(n对数n) 时间。

    我会注意到 n log k 涉及使用最多保留的最小堆的算法 k 元素。。。