mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-22 03:16:08 +00:00
102 lines
6.3 KiB
Markdown
102 lines
6.3 KiB
Markdown
# 演習
|
||
|
||
## 確認問題
|
||
|
||
### ハッシュ衝突後の探索方法
|
||
|
||
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" }
|