Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions Algorithm/Rolling Hash/other/same substring/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
了解しました。以下では、問題「**最長の重複部分文字列の長さを求める**」について、**Pythonコードに基づいて各処理を図解・詳細に解析**します。以下の4ステップに分けて説明します。

---

## 🎯 問題の要点

与えられた文字列 `S` において、**2つ以上の位置で一致する部分文字列が存在する長さ `k` の最大値**を求める。

---

## ✅ 全体構成(処理の流れ)

```text
入力: N, S
┌─────────────────────┐
│ 二分探索で長さ k を探索 │ ← k の候補は 0〜N-1
└─────────────────────┘
┌────────────────────┐
│ ローリングハッシュで │
│ 長さ k の部分文字列に │
│ 重複があるかをチェック │
└────────────────────┘
最大値を出力
```

---

## 🔍 詳細解析①:**ローリングハッシュの考え方**

### 🔸目的

文字列の部分列の比較を **定数時間** で行うために、**数値のようにハッシュ値を使って比較**します。

### 🔸イメージ図

例えば、文字列 `S = "NANANANANA"` に対して長さ `k = 3` の部分列をチェックする場合:

```
S = N A N A N A N A N A
└───┘
"NAN" を数値で表現 → ハッシュ値
```

各部分列 `"NAN"`, `"ANA"`, `"NAN"`, ... について、ハッシュ値を計算して **すでに出現したハッシュ値があるかを調べる**。

---

## 🔍 詳細解析②:**`compute_hash()` の処理**

関数 `compute_hash(s, length)` は、**長さ `length` の重複部分文字列が存在するか**をチェックする関数です。

### 🧮 ハッシュ計算の式

与えられた部分文字列 `s[i..i+length-1]` のハッシュ値は:

```
H = s[i] * B^(k-1) + s[i+1] * B^(k-2) + ... + s[i+k-1] * B^0 (mod MOD)
```

→ ローリングで更新:

```
H_new = (H_old - s[i] * B^(k-1)) * B + s[i+k]
```

### ⛓️ ローリングの流れ

```text
例: s = "NANANANANA", k = 3, BASE = 1000003

部分列 ハッシュ計算 ハッシュ値登録
-------- ----------------------------- --------------
"NAN" → ord('N') * B^2 + ord('A') * B + ord('N') → H1 → seen = {H1}
"ANA" → ローリングで計算 → H2 → seen = {H1, H2}
"NAN" → H3 = H1(衝突発生) → 重複検出!True
```

---

## 🔍 詳細解析③:**`find_max_duplicate_length()` の処理**

この関数は **二分探索で `k` の最大値**を探しています。

### 🔍 探索の流れ

```text
N = 10
範囲:k ∈ [0, N-1] = [0, 9]

初期:
left = 0
right = 9
result = 0

step1: mid = (0+9)//2 = 4 → 長さ4の重複があるか?
→ YES → result = 4, left = 5

step2: mid = (5+9)//2 = 7 → YES → result = 7, left = 8

step3: mid = (8+9)//2 = 8 → YES → result = 8, left = 9

step4: mid = 9 → NO → right = 8

終了: left > right → 最大長 = result = 8
```

---

## 💡 出力例での解析: `"NANANANANA"` のとき

### 🔠 文字列の構造

```
S = N A N A N A N A N A
↑ ↑ ↑
"NAN" が繰り返し出現
```

* 長さ 3 の "NAN"
* 長さ 4 の "NANA"
* 長さ 6 の "NANANA"
* 長さ 8 の "NANANANA"

→ 最長の重複 = 長さ **8**

---

## 💾 処理時間・メモリの見積り

| 処理 | 計算量 | 備考 |
| --------- | ------------ | ----------------------- |
| 二分探索 | `O(log N)` | 最大で \~16回探索 (N ≤ 50000) |
| 各kのハッシュ計算 | `O(N)` | ローリングで高速更新 |
| 合計 | `O(N log N)` | 実用十分高速 |
| メモリ | `O(N)` | ハッシュ値をセットに保持 |

---

## ✅ 結論まとめ

| 要素 | 内容 |
| ---------- | ------------------- |
| アルゴリズム | ローリングハッシュ + 二分探索 |
| 処理時間 | `O(N log N)`(高速) |
| メモリ使用量 | `O(N)`(効率的) |
| Pythonでの工夫 | 定数定義、高速I/O、MOD計算の工夫 |

---
Empty file.
Loading