【leetcode】692. 前K個高頻單詞

 

public static List<String> topKFrequent(String[] words, int k) {
        Map<String,Integer> map = new HashMap<>();
        // 通過map將每個元素出現的次數給統計出來,key是元素本身,value是元素出現的次數
        for (String word : words) {
            if (map.get(word)!=null){
                map.put(word,map.get(word)+1);
            }else{
                map.put(word,1);
            }
        }
        /**
         * 通過 java的 PriorityQueue實現一個小根堆
         * 堆中存放元素的邏輯
         * 1. 按照元素出現的次數由小到大排序(下面的else分支)因爲這樣可以保證在當前堆中,堆頂放的元素出現的次數是最小的
         *    如果下次有新元素到來,且新元素的次數比堆頂元素的大,則用新元素替換堆中元素次數最小的那個(也就是堆頂元素)
         * 2. 在堆中,如果兩個元素的次數相同,則按照元素的字母順序從大到小排序
         *    比如 "aaa" 和 "a" 二者都出現一次,這時應該按照字母順序從大到小排序,這樣可以保證字母順序大的更靠近堆頂
         *    如果新元素的次數比 1大,那麼被替換的就是 "aaa" (if分支)
         */
        PriorityQueue<Map.Entry<String,Integer>> priorityQueue = new PriorityQueue<>(k, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if (o1.getValue() == o2.getValue()){
                    return o2.getKey().compareTo(o1.getKey());
                }else{
                    return o1.getValue()-o2.getValue();
                }
            }
        });
        /**
         * 將元素放入到priorityQueue的兩種情況
         * 1. priorityQueue的size未滿(比k小),則直接將元素放進 priorityQueue (if分支)
         * 2. priorityQueue元素等於k,這時應該拿出堆頂元素和新到元素進行比較,比較規則有兩個
         *    1). 如果新到元素出現的次數比堆頂元素的大,則直接移除堆頂元素,將新到元素放入堆中(else分支中的if判斷的第一個條件)
         *    2). 如果新到元素出現的次數和堆頂元素的一樣,則比較新到元素和堆頂元素的字母順序,如果新到元素的字母順序比堆頂元素的小,則移除堆頂元素,放入新到元素
         */
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            if (priorityQueue.size()<k){
                priorityQueue.add(entry);
            }else{
                Map.Entry<String, Integer> peek = priorityQueue.peek();
                if ((entry.getValue()>peek.getValue()) ||
                        ((entry.getValue() == peek.getValue())
                                && (peek.getKey().compareTo(entry.getKey())>0))){
                    priorityQueue.remove();
                    priorityQueue.add(entry);
                }
            }
        }
        // 因爲 priorityQueue 實現的是小根堆,且堆內元素按字母順序由小到大排序,因此剛好和題目要求的順序反過來
        List<String> results = new ArrayList<>();
        for (int i = 0; i < k; i++) {
            results.add(priorityQueue.poll().getKey());
        }
        // 偷懶,直接用集合的翻轉方法(如果這一步自己實現的話,可以考慮用棧)
        Collections.reverse(results);
       return results;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章