1. 程式人生 > 其它 >【演算法】堆

【演算法】堆

堆(優先佇列)

思考:感覺能排序基本就不要用堆,沒有排序快

speed up repeated minimum computationns so that each computation takes logarithmic rather than linear time

堆是一種特別的二叉樹,滿足以下條件的二叉樹,可以稱之為堆:

  1. 完全二叉樹 從上到下,從左到右依次被填滿
  2. 每一個節點的值都必須大於等於或者小於等於其孩子節點的值。

特點:插入和刪除元素 時間複雜度為 O(logN);獲取最大值/最小值 時間複雜度為 O(1)

堆 有兩種型別:最大堆最小堆

預設的Comparator是升序,所以建出來的是最小堆

  1. 1337. 矩陣中戰鬥力最弱的 K 行 先按戰鬥力排,一樣再看行數誰靠後 建堆(最小堆)
  2. 703. 資料流中的第 K 大元素 建堆(最小堆),取數(最小的數放最上面,讓堆保持只有k個數,剩餘的可以直接捨棄)
  3. 1046. 最後一塊石頭的重量 建最大堆
  4. 劍指 Offer 40. 最小的k個數 但是排序比建堆執行快一點
  5. 2099. 找到和最大的長度為 K 的子序列 我用了兩個堆,先按照大小將k個數儲存到最小堆中,再按照陣列中的位置將前面堆中的元素放到新的最小堆中。新的最小堆中的元素即為答案

程式碼示例

703. 資料流中的第 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;
}

1046. 最後一塊石頭的重量

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();
}