Files
hello-algo/ja/docs/chapter_tree/exercises.md
T
2026-07-19 07:19:42 +08:00

127 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 演習
## 確認問題
### 完全二分木・充満二分木・充足二分木
次の 2 つの配列は二分木をレベル順に表しており、`None` は空き位置を表します。
- 木 A`[1, 2, 3, 4, 5, 6]`
- 木 B`[1, 2, 3, None, None, 6, 7]`
<!-- numbered-subquestions -->
1. どちらが完全二分木ですか?
2. どちらが充満二分木、つまりすべての非葉ノードが 2 つの子ノードを持つ二分木ですか?
3. この 2 つに充足二分木はありますか?それぞれ理由を説明してください。
??? success "解答"
1. 木 A は完全二分木です。最下層だけがすべて埋まっておらず、ノードが左から右へ隙間なく並んでいます。
木 B は完全二分木ではありません。最下層の左側に空き位置がある一方で、その右側にはノードがあるためです。
2. 木 B は充満二分木です。ノード 1 とノード 3 はそれぞれ 2 つの子ノードを持ち、それ以外のノードはすべて葉ノードです。
木 A は充満二分木ではありません。ノード 3 が左子ノード 6 だけを持つためです。
3. どちらも充足二分木ではありません。どちらの木も最下層がすべて埋まっていないためです。
### 同じ木を走査する 3 つの順序
配列 `[1, 2, 3, 4, 5, 6, 7]` をレベル順に完全二分木へ格納します。
<!-- numbered-subquestions -->
1. この木を描いてください。
2. 先行順・中間順・後行順走査の列をそれぞれ書いてください。
3. 中間順走査の列で、根ノード 1 の左側と右側にある 2 つの列は、木のどの部分にそれぞれ対応しますか?
??? success "解答"
1. この木は次のとおりです。
```text
1
/ \
2 3
/ \ / \
4 5 6 7
```
2. 先行順走査は `1, 2, 4, 5, 3, 6, 7`、
中間順走査は `4, 2, 5, 1, 6, 3, 7`、
後行順走査は `4, 5, 2, 6, 7, 3, 1` です。
3. 根ノード 1 の左側にある `4, 2, 5` は、左部分木の中間順走査の列です。
右側にある `6, 3, 7` は、右部分木の中間順走査の列です。
### 2 つの二分探索木を比較する
次の 2 つの列を、左から右へ順に空の二分探索木へ挿入します。
- 列 A`[4, 2, 6, 1, 3, 5, 7]`
- 列 B`[1, 2, 3, 4, 5, 6, 7]`
<!-- numbered-subquestions -->
1. それぞれの木で 7 を探索するときに通るノードを書いてください。
2. 高さを根ノードから最も遠い葉ノードまでに通る辺の数とすると、2 つの木の高さはそれぞれいくつですか?
3. 問い 1、2 の結果から、2 つの木で 7 を探索する効率は同じだと考えられますか?木の形と探索経路をもとに理由を説明してください。
??? success "解答"
1. 列 A から作った木では、探索経路は `4 → 6 → 7` です。
列 B から作った木では、探索経路は `1 → 2 → 3 → 4 → 5 → 6 → 7` です。
2. 1 つ目の木はすべての層が埋まっているため、高さは 2 です。2 つ目の木では各ノードが右の子だけを持ち、高さは 6 です。
3. 2 つの木で 7 を探索する効率は異なります。挿入順序によって二分探索木の形と高さが変わります。1 つ目の木で 7 を探索するときに通るノードは 3 つだけですが、
2 つ目の木では 7 つのノードを順に通ります。木が高いほど、最悪の場合に経路上で比較するノードが多くなります。
## プログラミング演習
### 二分木の最大の深さ
二分木の根ノード `root` が与えられます。各ノードには、整数値と左右の子ノードを指す参照が含まれています。
根ノードから最も遠い葉ノードまでに通る**ノード数**を、二分木の最大の深さとします。この木の最大の深さを返してください。空の木の最大の深さは 0 です。
再帰を使って求めてください。
??? tip "解法のヒント"
1. この問題ではノード数で深さを数えます。根ノードだけがある場合、最大の深さは 1 です
2. 再帰関数が、現在のノードを根とする部分木の最大の深さを返すようにします
3. 空のノードは 0 を返し、空でないノードは max(depth(left), depth(right)) + 1 を返します
[LeetCode](https://leetcode.com/problems/maximum-depth-of-binary-tree/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" }
### 二分木のレベル順走査
二分木の根ノード `root` が与えられます。キューを使い、上から下へ層ごとにすべてのノードを訪問してください。同じ層では、左から右の順に訪問します。
二次元配列を返してください。1 つ目の部分配列には根ノードがある層のノード値、2 つ目の部分配列には次の層のノード値を保存し、以降も同様に続けます。
二分木が空の場合は、空の配列を返してください。
??? tip "解法のヒント"
1. レベル順走査では先に入ったノードを先に訪問するため、キューを使います
2. 各回の開始時にキューに入っているノードは、ちょうど同じ層に属しています
3. 先にキューの長さを記録し、その個数のノードを取り出して、それぞれの子ノードを追加します
[LeetCode](https://leetcode.com/problems/binary-tree-level-order-traversal/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" }
### 二分探索木で k 番目に小さい要素
二分探索木には `n` 個のノードがあり、すべてのノード値は互いに異なります。
すべてのノード値を小さい順に並べたときの位置には、1 から番号を付けます。
根ノード `root` と、`1 <= k <= n` を満たす整数 `k` が与えられます。`k` 番目のノード値を返してください。
すべてのノード値を先に集めるのではなく、中間順走査の途中で答えを直接探してください。
??? tip "解法のヒント"
1. 二分探索木を中間順走査すると、ノード値を小さい順に訪問できます
2. 中間順走査では、左部分木、現在のノード、右部分木の順に処理します。現在のノードを訪問するとき、カウントに 1 を足します
3. カウントが初めて k になったとき、現在のノード値が答えです。それ以降は走査を続ける必要がありません
[LeetCode](https://leetcode.com/problems/kth-smallest-element-in-a-bst/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" }