mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-22 19:36:06 +00:00
9135647d93
Add dedicated chapter exercise sections and generated exercise pages for the English, Japanese, and Russian editions. Add navigation for all published languages while keeping Taiwan Traditional Chinese exercise pages generated at build time.
104 lines
6.4 KiB
Markdown
104 lines
6.4 KiB
Markdown
<!-- utils/exercises/publish_exercises.py により自動生成されています。直接編集しないでください。 -->
|
||
|
||
# 演習
|
||
|
||
## 確認問題
|
||
|
||
### ハッシュ衝突後の探索方法
|
||
|
||
5 個のバケットを持つハッシュテーブルがあり、ハッシュ関数は $h(x)=x \bmod 5$ です。衝突が起きた場合は、要素をそのバケットのリストへ順に格納します。
|
||
`[1, 6, 11, 7]` をこの順に挿入します。
|
||
|
||
<!-- numbered-subquestions -->
|
||
|
||
1. 0~4 番の各バケットの内容を書いてください。
|
||
2. 6 を探索するとき、最初にどのバケットへ行き、どの要素を順に調べますか?
|
||
3. 問い 1 で書いたバケットの内容では、後から挿入した要素が先に挿入した要素を上書きしていますか?この衝突処理方法と結び付けて理由を説明してください。
|
||
|
||
??? success "解答"
|
||
|
||
1. $1\bmod5=6\bmod5=11\bmod5=1$、$7\bmod5=2$ なので、各バケットは次のようになります。
|
||
|
||
```text
|
||
0: []
|
||
1: [1, 6, 11]
|
||
2: [7]
|
||
3: []
|
||
4: []
|
||
```
|
||
|
||
2. 6 を探索するときは、まず 1 番のバケットへ行き、1、6 の順に比較します。2 回目の比較で目的の値が見つかります。
|
||
|
||
3. ハッシュ値が同じであることは、同じバケットに入ることを表すだけで、それらの要素が等しいという意味ではありません。連鎖アドレス法では、衝突した要素をすべてバケット内に保存し、
|
||
探索時に 1 つずつ比較します。そのため、1、6、11 が互いに上書きされることはありません。
|
||
|
||
### ハッシュテーブルを拡張すると要素はどこへ移るか
|
||
|
||
連鎖アドレス法を使うハッシュテーブルには、もともと 5 個のバケットがあり、ハッシュ関数は $h(x)=x\bmod5$ です。
|
||
キー `[1, 6, 11]` はすべて 1 番のバケットに入っています。
|
||
|
||
ここでハッシュテーブルを 7 個のバケットに拡張し、ハッシュ関数も $h(x)=x\bmod7$ に変えます。
|
||
|
||
<!-- numbered-subquestions -->
|
||
|
||
1. 1、6、11 の新しいバケット番号をそれぞれ計算してください。
|
||
2. 拡張後、どのバケットに要素が入っていますか?
|
||
3. 拡張するとき、もとの 1 番のバケットにあるリストを、そのまま新しい 1 番のバケットへコピーできますか?問い 1、2 の結果と結び付けて理由を説明してください。
|
||
|
||
??? success "解答"
|
||
|
||
1. 新しいバケット番号は、それぞれ次のとおりです。
|
||
|
||
- $1\bmod7=1$。
|
||
- $6\bmod7=6$。
|
||
- $11\bmod7=4$。
|
||
|
||
2. 1 番のバケットには 1、4 番のバケットには 11、6 番のバケットには 6 が入ります。3 つのキーは同じバケットに集中しなくなります。
|
||
|
||
3. そのままコピーすることはできません。バケット番号は「キーをバケット数で割った余り」で決まります。バケット数が 5 から 7 に変わると、同じキーでも新しいバケット番号が変わる場合があるため、
|
||
各キーの位置を計算し直す必要があります。古い 1 番のバケットをそのままコピーすると、新しい式で 6 と 11 を探索したときに、
|
||
それぞれ 6 番と 4 番のバケットへ進むため、見つけられなくなります。
|
||
|
||
### 6 を削除した後も 11 を見つけられるか
|
||
|
||
5 個の位置を持つハッシュテーブルがあり、インデックスは `0~4`、ハッシュ関数は $h(x)=x\bmod5$ です。
|
||
衝突が起きた場合は、ハッシュ関数で得たインデックスから右へ進み、最初の空き位置を探します。
|
||
|
||
`[1, 6, 11]` をこの順に挿入します。
|
||
|
||
<!-- numbered-subquestions -->
|
||
|
||
1. 3 つの数は、最終的にそれぞれどのインデックスに入りますか?
|
||
2. 11 を探索するとき、どのインデックスを順に調べますか?
|
||
3. 6 を削除するとき、その位置を「一度も使われていない空き位置」に変え、探索は空き位置に出会うと終了するものとします。
|
||
この状態で 11 を探索すると、どうなりますか?その探索結果は正しいですか?問題がある場合は、どのように防げますか?
|
||
|
||
??? success "解答"
|
||
|
||
1. 1 はインデックス 1 に入ります。6 もインデックス 1 に対応するため、衝突後にインデックス 2 へ入ります。
|
||
11 もインデックス 1 から始め、使用中のインデックス 1、2 を順に飛ばして、最終的にインデックス 3 へ入ります。
|
||
|
||
2. 11 の探索では、インデックス `1、2、3` を順に調べ、インデックス 3 で見つけます。
|
||
|
||
3. インデックス 2 を「一度も使われていない」ことを表す空き位置に変えると、11 の探索ではインデックス 1 を調べた後、インデックス 2 で停止してしまい、
|
||
11 が存在しないと誤って判断します。削除時には「削除済み」の印を残す必要があります。
|
||
探索ではその印に出会っても次のインデックスを調べ続け(インデックス 4 を越えたらインデックス 0 に戻ります)、後の挿入ではその位置を再利用できます。
|
||
|
||
## プログラミング演習
|
||
|
||
### 2 つの文字列の文字構成を比較する
|
||
|
||
小文字の英字だけを含む 2 つの文字列 `s` と `t` が与えられます。
|
||
`s` の文字は自由に並べ替えられますが、文字の追加、削除、置換はできません。
|
||
|
||
並べ替えることで `t` を作れる場合は `true`、作れない場合は `false` を返してください。
|
||
文字列内の文字をソートせず、ハッシュテーブルを使って各文字の出現回数を記録してください。
|
||
|
||
??? tip "解法のヒント"
|
||
|
||
1. 2 つの文字列の長さが異なる場合、文字の構成も必ず異なります
|
||
2. ハッシュテーブルに各文字の個数を記録します。s を走査するとき、対応するカウントに 1 を足します
|
||
3. t を走査するとき、対応するカウントから 1 を引きます。最終的にすべてのカウントが 0 の場合に限り、文字の構成が同じです
|
||
|
||
[LeetCode](https://leetcode.com/problems/valid-anagram/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" }
|