二つのヒープパターン

中級

カテゴリ: arrays

概要

二つのヒープパターンは、データストリームの中央値や中間値を効率的に追跡するための手法です。このパターンでは、最大ヒープと最小ヒープの2つのヒープを使用して、データを2つのほぼ等しいグループに分割します。最大ヒープには小さい半分の要素が、最小ヒープには大きい半分の要素が格納され、これにより中央値を効率的に計算できます。

コードテンプレート

Java
Python
- データストリームの中央値
class MedianFinder {
    // 小さい半分の要素を格納する最大ヒープ
    private PriorityQueue<Integer> maxHeap;
    // 大きい半分の要素を格納する最小ヒープ
    private PriorityQueue<Integer> minHeap;
    
    public MedianFinder() {
        maxHeap = new PriorityQueue<>((a, b) -> b - a); // 最大ヒープ
        minHeap = new PriorityQueue<>(); // 最小ヒープ
    }
    
    public void addNum(int num) {
        // 最大ヒープが空か、数値が最大ヒープのトップ以下なら最大ヒープに追加
        if (maxHeap.isEmpty() || num <= maxHeap.peek()) {
            maxHeap.offer(num);
        } else {
            // それ以外は最小ヒープに追加
            minHeap.offer(num);
        }
        
        // ヒープのバランスを調整
        if (maxHeap.size() > minHeap.size() + 1) {
            minHeap.offer(maxHeap.poll());
        } else if (minHeap.size() > maxHeap.size()) {
            maxHeap.offer(minHeap.poll());
        }
    }
    
    public double findMedian() {
        if (maxHeap.size() == minHeap.size()) {
            // 要素数が偶数の場合、両方のヒープのトップの平均を返す
            return (maxHeap.peek() + minHeap.peek()) / 2.0;
        } else {
            // 要素数が奇数の場合、最大ヒープのトップを返す
            return maxHeap.peek();
        }
    }
}
Java

ひらめきのサポート

問題文に以下のようなキーワードや特徴がある場合、このパターンの適用を検討してみましょう。

二つのヒープ中央値メディアンデータストリーム最大ヒープ最小ヒープ優先キュー中間値バランス調整連続的な中央値

チャート式ひらめきポイント

問題を読んだときに、「ソート済み配列で何かを見つける」「二つの要素の関係を調べる」「効率的に配列を操作する」などの特徴があれば、 双指針パターンが適用できる可能性が高いです。特に、O(n²)の計算量を避けたい場合に有効です。

このパターンを使用する問題例

  • 1

    データストリームの中央値(Find Median from Data Stream): 要素を追加しながら中央値を効率的に計算する

  • 2

    スライディングウィンドウの中央値(Sliding Window Median): 固定サイズのウィンドウ内の中央値を計算する

  • 3

    最適な距離点(Minimize Max Distance to Gas Station): 最適な位置を見つけるために中央値の概念を使用

  • 4

    IPO(Initial Public Offering): 利益を最大化するためのプロジェクト選択問題

関連するパターン

heappriority-queuesliding-window