From eaa0aeea6bdfd74c11cbe0d9589a8b59e3f78c41 Mon Sep 17 00:00:00 2001 From: Keisuke KUDO <151166401+Apo-Matchbox@users.noreply.github.com> Date: Wed, 20 Aug 2025 11:01:07 +0900 Subject: [PATCH] Create 703. Kth Largest Element in a Stream.md --- 703. Kth Largest Element in a Stream.md | 88 +++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 703. Kth Largest Element in a Stream.md diff --git a/703. Kth Largest Element in a Stream.md b/703. Kth Largest Element in a Stream.md new file mode 100644 index 0000000..b695372 --- /dev/null +++ b/703. Kth Largest Element in a Stream.md @@ -0,0 +1,88 @@ +# [703. Kth Largest Element in a Stream](https://leetcode.com/problems/kth-largest-element-in-a-stream/description/) + +## Step1 +### 問題意図の考察 (Heap, PriorityQueue) +- 与えられた整数kに対して、k番目に高いスコアを返すclassを実装する。全てのスコアをソートしたリストにおけるk番目に大きいスコアを求める。 +- リアルタイムという点から、動的に更新されるデータの中で、常にk番目に高い値を効率的に取得する必要がある。 +- 幾つの要素が来るかはわからないので、効率性が求められる。 +- メモリの効率性を考えて、全部を保存するのではなく、その場で答えを出す。 + +### 解法を考える +- kthLargestのコンストラクタで、numsを読み込む。 +- add(int val)では、新しいスコアvalをヒープに追加。 +- カテゴリから推測するのは良くないが、heapで必要なメモリの確保か。ここにいきなりたどり着けるかな。 +- 解法が浮かばなかったので、回答を見る。 + +```cpp +#include +#include + +class KthLargest { + public: + KthLargest(int k, std::vector& nums) : k_(k) { + for (int num : nums) { + add(num); + } + } + + int add(int val) { + if (min_heap_.size() < k_) { + min_heap_.push(val); + } + else if (val > min_heap_.top()) { + min_heap_.pop(); + min_heap_.push(val); + } + return min_heap_.top(); + } + + private: + int k_; + std::priority_queue, std::greater> min_heap_; +}; + +/** + * Your KthLargest object will be instantiated and called as such: + * KthLargest* obj = new KthLargest(k, nums); + * int param_1 = obj->add(val); + */ + +``` + +## Step2 +- いくつかのrepoを確認してみたが、良し悪しの判断ができなかった。いくつかの選択肢を書いて、判断したい。 +- 「k番目に大きいスコアを教えて」-> 最大のk個だけ残しておけば、その中の最小値がk番目に大きい値になる。 +- priority_queue:優先度付きのキュー + -> *std::queue: FIFO, に対し、std::priority_queue: 常に一番大きな値が前に出る。https://en.cppreference.com/w/cpp/container/priority_queue.html + *話が逸れるが、物流の在庫管理の考え方:先入先出(FIFO)やプリンタのキュー管理など、実社会にあるのも面白い。 + *最大/最小を即座に取り出せる。O(log n)でpush/pop. top()はO(1). +- 時間がかかりすぎたので、他の解法の実装は別途。 + +```cpp +// 最大ヒープ(デフォルト) +std::priority_queue max_heap; + +// 最小ヒープ(今回) +std::priority_queue, std::greater> min_heap; + +// 操作 +min_heap.push(x); // 値を追加 +min_heap.top(); // 最小値を取得 +min_heap.pop(); // 最小値を削除 +min_heap.size(); + +``` +### データ構造とアルゴリズム +- このstep2の際に、AL-Strategiesの観点も今後の学習の際に考えた方が、良い方針が立ちそう。 + * Online Algorithm? 一件ずつ入力される前提 で動くアルゴリズム + * Heap Strategies 今回の実装 + * Top-K Elements 配列の中で上位k件を常に求める。 + * Streaming Process データが大量で、全部を保持できない。 +- 目的:stream が次々とくる。オンライン。 +- データサイズ:入力が無限に続く可能性有。全部保持したくない。 +- * k は大きい?小さい?:ここで躓いた。どのくらいの高さになるかはlognから割り出せるが、それが大きい?小さい?の判断が良くわからない。 + * lognの計算量の実測データ(ベンチマーク)・CPUクロックから判断できるみたい。別途深掘りする。 +- 更新:add(val)が何度も呼ばれる。 + +## Step3 +45min