mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-23 00:37:13 +00:00
Re-translate the Japanese version (#1871)
* Retranslate Japanese docs with GPT-5.4 * Retranslate Japanese code with GPT-5.4
This commit is contained in:
@@ -1,42 +1,42 @@
|
||||
# Top-k問題
|
||||
# Top-k 問題
|
||||
|
||||
!!! question
|
||||
|
||||
長さ$n$の順序付けられていない配列`nums`が与えられたとき、配列内の最大$k$個の要素を返してください。
|
||||
長さ $n$ の未整列配列 `nums` が与えられたとき、配列内で最大の $k$ 個の要素を返してください。
|
||||
|
||||
この問題について、まず2つの直接的な解法を紹介し、次により効率的なヒープベースの方法を説明します。
|
||||
この問題について、まずは発想が比較的直接的な 2 つの解法を紹介し、その後でより効率の高いヒープ解法を紹介します。
|
||||
|
||||
## 方法1:反復選択
|
||||
## 方法一:走査による選択
|
||||
|
||||
下図に示すように、$k$回の反復を実行し、各回で$1$番目、$2$番目、$\dots$、$k$番目に大きい要素を抽出できます。時間計算量は$O(nk)$です。
|
||||
以下の図に示すように $k$ 回の走査を行い、各ラウンドでそれぞれ第 $1$、$2$、$\dots$、$k$ 位の要素を取り出すことができます。時間計算量は $O(nk)$ です。
|
||||
|
||||
この方法は$k \ll n$の場合にのみ適しています。$k$が$n$に近い場合、時間計算量は$O(n^2)$に近づき、非常に時間がかかります。
|
||||
この方法は $k \ll n$ の場合にしか適していません。$k$ が $n$ にかなり近いと、時間計算量は $O(n^2)$ に近づき、非常に時間がかかるためです。
|
||||
|
||||

|
||||

|
||||
|
||||
!!! tip
|
||||
|
||||
$k = n$の場合、完全に順序付けられたシーケンスを得ることができ、これは「選択ソート」アルゴリズムと同等です。
|
||||
$k = n$ のとき、完全な昇順列を得ることができ、この場合は「選択ソート」アルゴリズムと等価になります。
|
||||
|
||||
## 方法2:ソート
|
||||
## 方法二:ソート
|
||||
|
||||
下図に示すように、まず配列`nums`をソートし、次に最後の$k$個の要素を返すことができます。時間計算量は$O(n \log n)$です。
|
||||
以下の図に示すように、まず配列 `nums` をソートし、その後で右端の $k$ 個の要素を返すことができます。時間計算量は $O(n \log n)$ です。
|
||||
|
||||
明らかに、この方法はタスクを「やりすぎ」ています。最大$k$個の要素を見つけるだけでよく、他の要素をソートする必要はありません。
|
||||
明らかに、この方法は必要以上の処理を行っています。なぜなら、必要なのは最大の $k$ 個の要素を見つけることだけであり、他の要素をソートする必要はないからです。
|
||||
|
||||

|
||||

|
||||
|
||||
## 方法3:ヒープ
|
||||
## 方法三:ヒープ
|
||||
|
||||
以下のプロセスに示すように、ヒープに基づいてTop-k問題をより効率的に解決できます。
|
||||
ヒープを用いることで、Top-k 問題をより効率的に解くことができます。手順は以下の図のとおりです。
|
||||
|
||||
1. 最小ヒープを初期化します。先頭要素が最小になります。
|
||||
2. まず、配列の最初の$k$個の要素をヒープに挿入します。
|
||||
3. $k + 1$番目の要素から開始し、現在の要素がヒープの先頭要素より大きい場合、ヒープの先頭要素を削除し、現在の要素をヒープに挿入します。
|
||||
4. 走査を完了した後、ヒープには最大$k$個の要素が含まれています。
|
||||
1. 最小ヒープを初期化し、そのヒープ頂点の要素が最小となるようにします。
|
||||
2. まず配列の先頭 $k$ 個の要素を順にヒープへ挿入します。
|
||||
3. $k + 1$ 番目の要素から開始し、現在の要素がヒープ頂点の要素より大きければ、ヒープ頂点の要素を取り出し、現在の要素をヒープへ挿入します。
|
||||
4. 走査が完了した後、ヒープに保持されているのが最大の $k$ 個の要素です。
|
||||
|
||||
=== "<1>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -62,12 +62,12 @@
|
||||
=== "<9>"
|
||||

|
||||
|
||||
サンプルコードは以下の通りです:
|
||||
サンプルコードは以下のとおりです。
|
||||
|
||||
```src
|
||||
[file]{top_k}-[class]{}-[func]{top_k_heap}
|
||||
```
|
||||
|
||||
合計$n$回のヒープ挿入と削除が実行され、最大ヒープサイズが$k$であるため、時間計算量は$O(n \log k)$です。この方法は非常に効率的で、$k$が小さい場合、時間計算量は$O(n)$に近づき、$k$が大きい場合でも、時間計算量は$O(n \log n)$を超えません。
|
||||
合計で $n$ 回のヒープ挿入と取り出しを行い、ヒープの最大長は $k$ であるため、時間計算量は $O(n \log k)$ です。この方法は非常に効率が高く、$k$ が小さいときは時間計算量が $O(n)$ に近づき、$k$ が大きいときでも $O(n \log n)$ を超えることはありません。
|
||||
|
||||
さらに、この方法は動的データストリームのシナリオに適しています。データを継続的に追加することで、ヒープ内の要素を維持し、最大$k$個の要素の動的更新を実現できます。
|
||||
さらに、この方法は動的データストリームの利用シーンにも適しています。データが継続的に追加される場合でも、ヒープ内の要素を保ち続けることで、最大の $k$ 個の要素を動的に更新できます。
|
||||
|
||||
Reference in New Issue
Block a user