一个有关堆的LeetCode问题的复杂度分析

来源:8-7 Leetcode上优先队列相关问题

Genpeng

2018-12-06

波波老师:
您好!

我的问题和LeetCode第692题【前K个高频单词】有关,下面是问题的描述:


给一非空的单词列表,返回前 k 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率,按字母顺序排序。

示例 1:

输入: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
    注意,按字母顺序 "i" 在 "love" 之前。

示例 2:

输入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
输出: ["the", "is", "sunny", "day"]
解析: "the", "is", "sunny" 和 "day" 是出现次数最多的四个单词,
    出现次数依次为 4, 3, 2 和 1 次。

注意:

  1. 假定 k 总为有效值, 1 ≤ k ≤ 集合元素数。

  2. 输入的单词均由小写字母组成。

扩展练习:

  1. 尝试以 O(n log k) 时间复杂度和 O(n) 空间复杂度解决。


我的问题是这样的,这道题可以采用优先队列进行求解(维护一个只有K个元素的最小堆),而我尝试借助桶排序进行求解,但是有一小段代码不知道如何分析时间复杂度,所以向波波老师求助。

代码如下:

/**
 * This is the solution of No. 692 problem in the LeetCode by using bucket sort,
 * the website of the problem is as follow:
 * https://leetcode.com/problems/top-k-frequent-words/
 *
 * @author  StrongXGP (xgp1227@gmail.com)
 * @date    2018/12/05
 */
public class Solution4 {
    public List<String> topKFrequent(String[] words, int k) {
        // 1. 统计单词的词频
        //    时间复杂度为 O(n)
        Map<String, Integer> wordFreq = new HashMap<>(16);
        for (String word : words) {
            wordFreq.put(word, wordFreq.getOrDefault(word, 0) + 1);
        }

        // 2. 使用桶排序将单词按照词频进行分组
        //    时间复杂度为 O(n)
        List<String>[] bucket = new List[words.length + 1];
        for (String word : wordFreq.keySet()) {
            int freq = wordFreq.get(word);
            if (bucket[freq] == null) {
                bucket[freq] = new ArrayList<>();
            }
            bucket[freq].add(word);
        }

        // >>> ??? 此处即为不知道如何进行时间复杂度分析的地方 ??? <<<
        // 3. 取出 top k 词频的单词(备注:词频相同的单词按照字母顺序排列)
        List<String> result = new ArrayList<>();
        for (int i = words.length; i > 0 && result.size() < k; --i) {
            if (bucket[i] != null) {
                if (bucket[i].size() > 1) {
                    Collections.sort(bucket[i]);
                }
                result.addAll(bucket[i]);
            }
        }
        return result.subList(0, k);
    }
}

下面这段代码不知道该如何分析时间复杂度。
图片描述

麻烦老师了。

写回答

1回答

liuyubobobo

2018-12-06

这里可以用均摊分析。


最好的情况,显然是每个桶里只有一个元素,此时循环中的复杂度是O(1)的;

但是最坏的情况,某一个桶中有全部元素。里面的排序复杂度是O(nlogn)的。但是,这样的桶最多只可能有一个,摊到循环中,每一次平均摊到是O(logn);

对于其他情况,比如两个桶是n/2,或者三个桶是n/3,或者四个桶是a,b,c,d,但a+b+c+d=n,把其中所有的排序时间加起来,再均摊到每一次循环中,都小于logn


所以这一部分的时间复杂度可以认为是O(nlogn)的:)


继续加油!:)

0
1
Genpeng
谢谢波波老师,( ^ _ ^ ) V
2018-12-06
共1条回复

玩转数据结构

动态数组/栈/队列/链表/BST/堆/线段树/Trie/并查集/AVL/红黑树…

6221 学习 · 1704 问题

查看课程