471. 最高频的K个单词

描述

给一个单词列表,求出这个列表中出现频次最高的K个单词。

注意事项

你需要按照单词的词频排序后输出,越高频的词排在越前面。如果两个单词出现的次数相同,则词典序小的排在前面。

样例

给出单词列表:

[
    "yes", "lint", "code",
    "yes", "code", "baby",
    "you", "baby", "chrome",
    "safari", "lint", "code",
    "body", "lint", "code"
]

如果 k =3, 返回["code", "lint", "baby"]
如果 k =4, 返回["code", "lint", "baby", "yes"]

挑战
用 O(nlogk)的时间和 O(n) 的额外空间完成。
如果你能够用 O(n) 的时间和 O(k) 的额外空间,那就更好不过了。

代码

class Pair {
    String key;
    int value;
    
    Pair(String key, int value) {
        this.key = key;
        this.value = value;
    }
}

public class Solution {
    /**
     * @param words an array of string
     * @param k an integer
     * @return an array of string
     */
    private Comparator pairComparator = new Comparator() {
        public int compare(Pair left, Pair right) {
            // return 正数说明左边单词出现的频次高
            if (left.value != right.value) {
                return left.value - right.value;
            }
            // 频次相同时,如果return 1说明左边词序小,把left.key放前面
            return right.key.compareTo(left.key);
        }
    };
    
    public String[] topKFrequentWords(String[] words, int k) {
        if (k == 0) {
            return new String[0];
        }
        
        // 统计每个单词出现的频次
        HashMap counter = new HashMap<>();
        for (String word : words) {
            if (counter.containsKey(word)) {
                counter.put(word, counter.get(word) + 1);
            } else {
                counter.put(word, 1);
            }
        }
        
        PriorityQueue Q = new PriorityQueue(k, pairComparator);
        for (String word : counter.keySet()) {
            Pair peak = Q.peek();
            Pair newPair = new Pair(word, counter.get(word));
            if (Q.size() < k) {
                Q.add(newPair);
            // newPair出现频次高或者词序小时,取代最小堆的堆顶元素
            } else if (pairComparator.compare(newPair, peak) > 0) {
                Q.poll();
                Q.add(newPair);
            }
        }
        
        String[] result = new String[k];
        int index = 0;
        while (!Q.isEmpty()) {
            result[index++] = Q.poll().key;
        }
        
        // reverse
        // 第一个和倒数第一个交换,第二个和倒数第二个交换,依次类推
        for (int i = 0; i < index / 2; i++) {
            String temp = result[i];
            result[i] = result[index - i - 1];
            result[index - i - 1] = temp;
        }
        
        return result;
     }
}

CompareTo用法

先读取出字符串的第一个“字母”进行比较,比较的方法是ascii码表的值(字符所对应的十进制值),如果前面的大那么返回1,后面的大返回-1;此位置相同,继续比较下一位,直到最后一位,如果都相同的话,就返回0;

你可能感兴趣的:(471. 最高频的K个单词)