Skip to content
Open
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
159 changes: 159 additions & 0 deletions memo.md
Original file line number Diff line number Diff line change
@@ -1 +1,160 @@
# Step1

## アプローチ

* maximumdepthと同様に考えられそう
* recursion
* 左の部下には, 左の部下を頭として一番小さい深さを教えてもらう
* 右の部下には, 右の部下を頭として一番小さい深さを教えてもらう
* 自分は, 受け取った二つのうち小さい方+1が最小だと上司に伝える
* bfs
* 各レベルごとに見ていく
* 子を持たないノードができたら終了
* dfs
* 子を持たないノードに到達した時に, minimum_depthを更新する
* 計算量は, O(N). ノード数をNとする
* recursionをする場合の最大再帰スタックはN

## Code1-1 (Recursion) - solved 4:56

```python
from typing import Optional


# 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

if root.left is None and root.right is None:
return 1

if root.left is None:
return self.minDepth(root.right) + 1

if root.right is None:
return self.minDepth(root.left) + 1

return min(self.minDepth(root.left), self.minDepth(root.right)) + 1

```

## Code1-2 (DFS) - solved 2:40

```python
from typing import Optional


# 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

frontier = [(root, 1)]
minimum_depth = float("inf")
while frontier:
node, depth = frontier.pop()
if node.left is None and node.right is None:
minimum_depth = min(minimum_depth, depth)
continue
if node.left is not None:
frontier.append((node.left, depth + 1))
if node.right is not None:
frontier.append((node.right, depth + 1))
return minimum_depth

```

## Code1-3 (BFS) - solved 2:42

```python
from typing import Optional
from collections import deque


# 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

depth = 0
frontier = deque()
frontier.append(root)
while frontier:
num_cur_frontier = len(frontier)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちらのコメントをご参照ください。
hemispherium/LeetCode_Arai60#10 (comment)

また、 frontier は一つだけ存在していて、その中に node が複数存在している、と考える人もいると思います。その場合、 num_cur_frontier は不自然に感じられます。

自分なら num_nodes_in_level と名付けると思います。

depth += 1
for _ in range(num_cur_frontier):
Copy link
Copy Markdown

@nodchip nodchip Mar 17, 2026

Choose a reason for hiding this comment

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

deque 一つだけを使い、現在のレベルのノードの個数だけループを回すという書き方は、初見の方にとってはもしかしたらわかりづらいかもしれません。最近はこちらの書き方のほうがメジャーなのでしょうか…。
list を 2 つ使って、片方から展開したノードをもう片方に入れるやり方や、 deque の中に要素とレベルの tuple を入れるやり方のほうが良く見かけるかもしれません。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

最近はこちらの書き方のほうがメジャーなのでしょうか…。

自分がそれしか知らなかったので使っていただけですね。最近は提示していただいたリストを二つ使うやり方にしています。

node = frontier.popleft()
if node.left is None and node.right is None:
return depth
if node.left is not None:
frontier.append(node.left)
if node.right is not None:
frontier.append(node.right)

raise ValueError()

```

# 他の人のコードやコメント集を見る

今回からarai60完走者のを見ることにした

* 1 - https://github.com/mamo3gr/arai60/pull/20/files
* BFS
* BFSで`deque`を使わない方法をやっている.
* 注目している主役がわかりやすい
* BFSのエラー文をどうするか迷って空白にしたが, `something went wrong`くらいアバウトでもいいのか
* `raise RuntimeError("You can not reach here. There is something wrong in the implementation")`
* RuntimeErrorを使うのは考えに及ばなかった
* DFS
* `root.left`と`root.right`をループで回している
* バイナリツリーじゃなくなった場合でも応用が効きそう
* 変数`is_leaf`とかにif文の条件をまとめたら読みやすくなりそう
* 再帰
* `root.left`と`root.right`をループで回す方法を再帰でもやっている
* 2 - https://github.com/Satorien/LeetCode/pull/22/files
* 帰りがけをstackにしたものがコメントで紹介されていた
* https://github.com/potrue/leetcode/pull/22#discussion_r2112567800
* 一般的にみんながstackで行うdfsは行きがけ
* 一方で, 一般的にみんなが再帰で行うdfsは帰りがけ
* 3 - https://github.com/ryoooooory/LeetCode/pull/25/files
* whileの中でループすることが決まっているので`while(true)`を使っていた
* そうしたら`raise RuntimeError`をしなくてよくなる
* 4 - https://github.com/naoto-iwase/leetcode/pull/21/files
* 再帰関数の終了処理と, そもそもの与えられた引数の確認が別なら内部関数で処理を分けるのが見やすそう
* BFSのやり方についてのコメントがあった

* ちなみに, 多くの人は再帰=DFSという表記をしているが, 本PRでは, DFSはstackを使った再帰を表すこととする

```
あと、BFS をするのに
node_queue
num_node_in_level
で数を数えて、次のレベルに行くの、少しややこしいと思っています。データの整合性が取れているということは、読んでいる人からすると全部読み終わらないと分からないからです。書いている人は分かるわけですが。
つまり、一つの変数に、2つの違う種類のものを入れておいて、その境界を個数で管理しているわけですよね。
```
27 changes: 27 additions & 0 deletions step1-1_recursion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import Optional


# 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

if root.left is None and root.right is None:
return 1

if root.left is None:
return self.minDepth(root.right) + 1

if root.right is None:
return self.minDepth(root.left) + 1

return min(self.minDepth(root.left), self.minDepth(root.right)) + 1

28 changes: 28 additions & 0 deletions step1-2_dfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Optional


# 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

frontier = [(root, 1)]
minimum_depth = float("inf")
while frontier:
node, depth = frontier.pop()
if node.left is None and node.right is None:
minimum_depth = min(minimum_depth, depth)
continue
if node.left is not None:
frontier.append((node.left, depth + 1))
if node.right is not None:
frontier.append((node.right, depth + 1))
return minimum_depth
34 changes: 34 additions & 0 deletions step1-3_bfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import Optional
from collections import deque


# 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

depth = 0
frontier = deque()
frontier.append(root)
while frontier:
num_cur_frontier = len(frontier)
depth += 1
for _ in range(num_cur_frontier):
node = frontier.popleft()
if node.left is None and node.right is None:
return depth
if node.left is not None:
frontier.append(node.left)
if node.right is not None:
frontier.append(node.right)

raise ValueError()

26 changes: 26 additions & 0 deletions step2-1_recursion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import Optional


# 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

def helper_minDepth(node: TreeNode) -> int:
if node.left is None and node.right is None:
return 1
if node.left is None:
return helper_minDepth(node.right) + 1
if node.right is None:
return helper_minDepth(node.left) + 1
return min(helper_minDepth(node.left), helper_minDepth(node.right)) + 1

return helper_minDepth(root)
28 changes: 28 additions & 0 deletions step2-2_dfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Optional


# 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

frontier = [(root, 1)]
minimum_depth = float("inf")
while frontier:
node, depth = frontier.pop()
if node.left is None and node.right is None:
minimum_depth = min(minimum_depth, depth)
continue
if node.left is not None:
frontier.append((node.left, depth + 1))
if node.right is not None:
frontier.append((node.right, depth + 1))
return minimum_depth
32 changes: 32 additions & 0 deletions step2-3_bfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from typing import Optional
from collections import deque


# 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

frontier = deque([root])
depth = 1
while True:
next_frontier = deque()
while frontier:
node = frontier.popleft()
if node.left is None and node.right is None:
return depth
if node.left is not None:
next_frontier.append(node.left)
if node.right is not None:
next_frontier.append(node.right)
frontier = next_frontier
depth += 1

30 changes: 30 additions & 0 deletions step3-1_recursion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 1st 2:10
# 2nd 1:05
# 3rd 1:03

from typing import Optional


# 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

def minDepth_helper(node):
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

helper関数を定義する必要はないように思いました。
minDepthの再帰で書けると思います。
手前味噌で恐縮ですが参考にしてください。
https://github.com/tom4649/Coding/blob/111.Minimum-Depth-of-Binary-Tree/111/sol2.py

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

これは意図としては最初のroot is Noneは再帰とは別ロジックと捉えて処理を分離したいというのがありました。

このコメントを読んだからですね。
mamo3gr/arai60#20 (comment)

入力がNoneでないことをminDepth()本体で確認してから,引数にNoneでないTreeNodeをとる再帰用のヘルパー関数(12行目以下の内容をそのまま関数化)を用意してそちらにrootを渡す方が,作業の分離という意味でわかりやすいと感じます.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

なるほど、最初の呼び出し以外ではNoneが与えられることはないですね。
勉強になりました。

if node.left is None and node.right is None:
return 1
if node.left is None:
return minDepth_helper(node.right) + 1
if node.right is None:
return minDepth_helper(node.left) + 1
return min(minDepth_helper(node.left), minDepth_helper(node.right)) + 1

return minDepth_helper(root)
Loading