【演算法】堆
阿新 • • 發佈:2022-04-15
堆(優先佇列)
思考:感覺能排序基本就不要用堆,沒有排序快
speed up repeated minimum computationns so that each computation takes logarithmic rather than linear time
堆是一種特別的二叉樹,滿足以下條件的二叉樹,可以稱之為堆:
- 完全二叉樹 從上到下,從左到右依次被填滿
- 每一個節點的值都必須大於等於或者小於等於其孩子節點的值。
特點:插入和刪除元素 時間複雜度為 O(logN);獲取最大值/最小值 時間複雜度為 O(1)
堆 有兩種型別:最大堆 和 最小堆。
預設的Comparator是升序,所以建出來的是最小堆
- 1337. 矩陣中戰鬥力最弱的 K 行 先按戰鬥力排,一樣再看行數誰靠後 建堆(最小堆)
- 703. 資料流中的第 K 大元素 建堆(最小堆),取數(最小的數放最上面,讓堆保持只有k個數,剩餘的可以直接捨棄)
- 1046. 最後一塊石頭的重量 建最大堆
- 劍指 Offer 40. 最小的k個數 但是排序比建堆執行快一點
- 2099. 找到和最大的長度為 K 的子序列 我用了兩個堆,先按照大小將k個數儲存到最小堆中,再按照陣列中的位置將前面堆中的元素放到新的最小堆中。新的最小堆中的元素即為答案
程式碼示例
public int[] kWeakestRows(int[][] mat, int k) { int m = mat.length, n = mat[0].length; List<int[]> power = new ArrayList<>(); // 用二分法找到每一行的最後一個1的位置 // 如果最後一個1的位置為pos,則該行軍人數為pos + 1 for(int i = 0; i < m; i++) { int left = 0, right = n - 1, pos = -1; while(left <= right) { int mid = (left + right) >> 1; if(mat[i][mid] == 1) { pos = mid; left = mid + 1; } else { right = mid - 1; } } power.add(new int[]{pos + 1, i}); } PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>() { public int compare(int[] pair1, int[] pair2) { if(pair1[0] != pair2[0]) { return pair1[0] - pair2[0]; } else { return pair1[1] - pair2[1]; } } } ); for(int[] pair : power) { pq.offer(pair); } int[] ans = new int[k]; for(int i = 0; i < k; i++) { ans[i] = pq.poll()[1]; } return ans; }
public int lastStoneWeight(int[] stones) { // 匿名類 PriorityQueue<Integer> pq= new PriorityQueue<Integer>(new Comparator<Integer>() { public int compare(Integer o1, Integer o2) { return o2 - o1; } }); // Lambda表示式 PriorityQueue<Integer> pq= new PriorityQueue<Integer>((o1, o2) -> (o2 - o1)); for(int stone : stones) { pq.offer(stone); } while(pq.size() != 1 && pq.size() != 0) { int y = pq.poll(); int x = pq.poll(); if(x != y) { pq.offer(y - x); } } return pq.isEmpty() ? 0 : pq.poll(); }