leetcode筆記_優先佇列經典問題(N中選出前M)
阿新 • • 發佈:2018-12-22
一個關於優先佇列的經典問題
在N個元素中選出前M個元素(N遠大於M時)
- 思路一:對N的元素進行排序,然後選出前M個元素,時間複雜度為O(NlogN)(採用快排或歸併排序等高階排序演算法)
- 思路二:使用優先佇列,可以將時間複雜度降低為O(NlogM)。具體實現:使用優先佇列維護M個元素,即每次向優先佇列中加入一個元素時,需要將當前佇列中的最小元素替換出去,保證佇列中的M個元素是當前遍歷過的元素中的最大的前M個。
347. 前K個高頻元素
給定一個非空的整數陣列,返回其中出現頻率前 k 高的元素。
示例 1:
輸入: nums = [1,1,1,2,2,3], k = 2 輸出: [1,2]示例 2:
輸入: nums = [1], k = 1 輸出: [1]說明:
- 你可以假設給定的 k 總是合理的,且 1 ≤ k ≤ 陣列中不相同的元素的個數。
- 你的演算法的時間複雜度必須優於 O(n log n) , n 是陣列的大小。
class Solution { public List<Integer> topKFrequent(int[] nums, int k) { //將陣列放入一個記錄頻次的Map中 TreeMap<Integer, Integer> map = new TreeMap<>(); for(int num : nums){ if(map.containsKey(num)){ map.put(num, map.get(num)+1); }else{ map.put(num, 1); } } //通過一個最多可容納K個元素的優先佇列來選出出現頻率前k高的k個元素 //優先佇列在構造時,通過傳入的外部比較器Comparator 可以定義優先佇列裡元素型別的比較方法 //這裡,優先佇列裡存放Integer, 傳入的外部比較器重新定義了比較兩個整型型別的方法,即比較它們出現的頻次 //Java內建優先佇列的底層是最小堆,所以出隊的是根據比較器定義的最小元素 PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>(){ @Override public int compare(Integer a, Integer b){ //使用匿名內部類實現Comparator介面,重新定義了比較兩個整型型別的方法,即比較它們出現的頻次 return map.get(a)-map.get(b); } }); for(int num : map.keySet()){ if(pq.size()<k){ pq.add(num); }else{ if(map.get(num)>map.get(pq.peek())){ //優先佇列內只保持k個元素,入隊時需要和優先順序最高的元素((頻次)最小的元素)作比較 pq.remove(); pq.add(num); } } } //根據要求,返回一個List ArrayList<Integer> list = new ArrayList<>(); while(!pq.isEmpty()){ list.add(pq.remove()); } return list; } }