二つのヒープパターン
カテゴリ: arrays
概要
二つのヒープパターンは、データストリームの中央値や中間値を効率的に追跡するための手法です。このパターンでは、最大ヒープと最小ヒープの2つのヒープを使用して、データを2つのほぼ等しいグループに分割します。最大ヒープには小さい半分の要素が、最小ヒープには大きい半分の要素が格納され、これにより中央値を効率的に計算できます。
コードテンプレート
- データストリームの中央値
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();
}
}
}
ひらめきのサポート
問題文に以下のようなキーワードや特徴がある場合、このパターンの適用を検討してみましょう。
チャート式ひらめきポイント
問題を読んだときに、「ソート済み配列で何かを見つける」「二つの要素の関係を調べる」「効率的に配列を操作する」などの特徴があれば、 双指針パターンが適用できる可能性が高いです。特に、O(n²)の計算量を避けたい場合に有効です。
このパターンを使用する問題例
- 1
データストリームの中央値(Find Median from Data Stream): 要素を追加しながら中央値を効率的に計算する
- 2
スライディングウィンドウの中央値(Sliding Window Median): 固定サイズのウィンドウ内の中央値を計算する
- 3
最適な距離点(Minimize Max Distance to Gas Station): 最適な位置を見つけるために中央値の概念を使用
- 4
IPO(Initial Public Offering): 利益を最大化するためのプロジェクト選択問題
このパターンを使う問題
このパターンを適用して解くことができる実際の問題です。
データストリームの中央値
データストリームから中央値を見つけるためのデータ構造を設計してください。 中央値とは、ソートされたデータセットの中央に位置する値です。データの数が奇数の場合、中央値は中央の要素です。データの数が偶数...
2つのソート配列の中央値
2つのソート済み配列 `nums1` と `nums2` が与えられたとき、2つの配列をマージした結果の中央値を求めてください。 全体の実行時間の複雑度は O(log(m+n)) である必要がありま...
配列内のK番目に大きい要素
整数の配列 nums と整数 k が与えられたとき、配列内のk番目に大きい要素を見つけて返してください。 k番目に大きい要素とは、配列をソートした後にインデックス n-k の位置にある要素のことです...
頻出上位K要素
整数の配列 nums と整数 k が与えられたとき、配列内で最も頻繁に出現する k 個の要素を返してください。任意の順序で返すことができます。...