Skip to content
Open
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
79 changes: 79 additions & 0 deletions Python3/111. Minimum Depth of Binary Tree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
## Step 1. Initial Solution

- 葉が出てきたら終了できるBFSで実装するのが自然に感じた
- rootがNoneの時の返り値は0じゃないといけないらしい
- 初めはValueErrorにしていたが駄目だった

```python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if root is None:
return 0
remaining_nodes_and_depths: List[Tuple[TreeNode, int]] = deque([(root, 1)])
while remaining_nodes_and_depths:
node, depth = remaining_nodes_and_depths.popleft()
if node.left is None and node.right is None:
return depth
if node.left is not None:
remaining_nodes_and_depths.append((node.left, depth + 1))
if node.right is not None:
remaining_nodes_and_depths.append((node.right, depth + 1))
raise ValueError('Invalid nodes')
```

### Complexity Analysis

- 時間計算量:O(n)
- 最悪の場合でも全てのノードを見る前に終わる
- 空間計算量:O(n)

## Step 2. Alternatives

- min_depthを定義している人がいたがBFSなら不要という認識なので疑問に思った
- depthをノードごとに保持しない方法もあるが、二重ループになって深くなるので微妙かなと感じた
- ただ、こちらのやり方を好む人も多そう
- 最後にエラー処理を入れているがあまり同じことをしてる人はいなさそうなので不要かもしれない
- 木構造の高さの測り方として行きがけと帰りがけ・上から配ると下から集めるといった表現をしている人がいた
- 高さを知りたいだけなら行きがけで良いのかなと感じた
- あまり帰りがけのメリットが分からなかった
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

高さを知りたいだけならば、行きでよいのは確かです。
もっとも、色々複雑なことをしないといけない場合はあるので、ある程度幅広く選択肢が見えた上で、どうしたいかを選択したほうがいいですね。

変わり種で、こういう書き方もありますよ。(帰りがけをループに直したもの。)
potrue/leetcode#22 (comment)

- 再帰で書くと自然なのはこちらになりそう

```python
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if root is None:
return 0
if root.left is None and root.right is None:
return 1
if root.left is None:
return 1 + self.minDepth(root.right)
if root.right is None:
return 1 + self.minDepth(root.left)
return 1 + min(self.minDepth(root.right), self.minDepth(root.left))
```

## Step 3. Final Solution

- 3回のうち1回は二重ループで書いてみたが最後はほぼStep 1と同じなものがしっくりきた

```python
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if root is None:
return 0
remaining_nodes_and_depths: List[Tuple[TreeNode, int]] = deque([(root, 1)])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好みだとは思いますが、個人的には nodes_and_depths くらいの長さの変数名でもよいのかなと感じました。比較的コード量が短く処理も簡潔で queue として使っていることがわかりやすいので。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

右辺を見たら型はわかる、List ではない、の2点で書かなくても良いかなと思いました。型を deque[tuple[TreeNode, int]] のように書くのはNGなのでしょうか?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらの書き方でも問題ないようでした。ご指摘ありがとうございます。
個人的には中に変な型を入れたときに型チェックしてくれると嬉しいのでリストやdequeなどは型を書いておこうと思っています

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちなみにどういう型チェックを想定されていますか?

while remaining_nodes_and_depths:
node, depth = remaining_nodes_and_depths.popleft()
if node is None:
continue
if node.left is None and node.right is None:
return depth
remaining_nodes_and_depths.append((node.left, depth + 1))
remaining_nodes_and_depths.append((node.right, depth + 1))
```