Skip to content

111. Minimum Depth of Binary Tree#20

Open
tom4649 wants to merge 3 commits intomainfrom
111.Minimum-Depth-of-Binary-Tree
Open

111. Minimum Depth of Binary Tree#20
tom4649 wants to merge 3 commits intomainfrom
111.Minimum-Depth-of-Binary-Tree

Conversation

@tom4649
Copy link
Copy Markdown
Owner

@tom4649 tom4649 commented Mar 15, 2026

Copy link
Copy Markdown

@dxxsxsxkx dxxsxsxkx left a comment

Choose a reason for hiding this comment

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

いろいろなパターンがconciseにまとめられていて、良いと思いました。

return 0
if root.right is None and root.left is None:
return 1
min_depth = float("inf")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ここの初期値はどんな感じで決められましたか?

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.

intのinfがないので、floatのinfで代用しました
(質問の意図に合っているか分かりませんが)

Comment on lines +8 to +11
- sol1.py: トップダウン + ループ(BFS)
- sol2.py: ボトムアップ + 再帰(DFS)
- sol3.py: トップダウン + 再帰(DFS)
- sol4.py: ボトムアップ + ループ(DFS / スタック)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

結局、実務で「実装してくれ」と言われたときに、どんな理由でどれを選ぶのか、が検討できていると良いと思います。

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.

たしかにそうですね。メモを追記しました。

111/sol1.py Outdated
def minDepth(self, root: Optional[TreeNode]) -> int:
if root is None:
return 0
que = deque()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

中途半端な省略は避けたほうが無難です。この練習会では frontier や、depth_and_nodes (入っているもの)などの命名をよく見かけます。

Suggested change
que = deque()
queue = deque()

111/sol1.py Outdated
depth, node = que.popleft()
if node.right is None and node.left is None:
return depth
for child in [node.right, node.left]:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

特に理由がなければ、left -> right の順が自然に感じました。事情があるならコメントしておくと良いでしょう。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

あと、[node.right, node.left] の配列が都度生成されることは意識しておくと良いと思います(オーバーヘッドとしては大したものではないでしょうが)。

Copy link
Copy Markdown
Owner Author

@tom4649 tom4649 Mar 25, 2026

Choose a reason for hiding this comment

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

順序を変えてtupleにしました。たしかに配列生成のオーバーヘッドが発生しますね

111/sol3.py Outdated
Comment on lines +9 to +12
min_depth = float("inf")
if root is None:
return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

特別なケースは先に返してしまって、その後になって必要な変数を宣言したいです。

Suggested change
min_depth = float("inf")
if root is None:
return 0
if root is None:
return 0
min_depth = float("inf")

111/sol3.py Outdated
Comment on lines +15 to +16
if node is None:
return
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

child のNoneチェックは済んでいる、かつ root のNoneチェックは済んでいるので、ここではチェック不要そうです。

Suggested change
if node is None:
return

111/sol3.py Outdated
if child is None:
continue
dfs(child, depth + 1)
return
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
return

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.

たしかに不要ではありますね。省略するのが普通なんでしょうか。一応削除しようと思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

「一応」が気になったのでコメントします。削除すべきかどうかの基準・価値観を自分なりに持つことと、普通=一般的にはどうなのかを知ることが、この練習会での目的のひとつに思います(ただし、「普通」には幅があることに注意してください。実務上は所属チームに合わせるのが良いと思います)。これを踏まえて、何を考えてそうしたのか言語化してみてはどうでしょうか。

末尾に到達したら関数がreturn (None) するのはPythonの仕様で、私は、ここはそれに該当するので、特別な事情がない限りは不要(むしろ読み手が「何か事情があるのか?」と無駄に勘ぐってしまう)と考えました。一方で、「ここまで関数を抜けるときはreturnしてきたので、最後もそうするべきだ(一貫性がある)」という主張も、理屈の上では成り立つように思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

また、「普通」のサンプルとして、この練習会ではPEP8やGoogleのスタイルガイドが取り上げられることが多いです。これらの中も探してみると良いでしょう。ちなみに私がざっと調べたところ、「末尾のreturnは書くな」という文は見つけられませんでした。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

おっしゃるとおりで、PEP8 には明示的に書くなとは書いてないですね。ただ、値を返す関数のときには末尾に return None と書けとありますね。
ただ、Pylint に useless-return という項目があったりと、警告する linter は多そうです。
https://pylint.readthedocs.io/en/latest/user_guide/messages/refactor/useless-return.html
https://peps.python.org/pep-0008/#programming-recommendations:~:text=Be%20consistent%20in%20return%20statements.

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.

Pythonではreturn文を書かなくてもNoneを返す仕様になっているので、必要のないreturnは書かないようにしようと思います。
曖昧な点を残さずに課題に取り組むことも意識しようと思います。
(GoogleのStyleガイドも見てみましたが、言及されている箇所は見つかりませんでした)
https://google.github.io/styleguide/pyguide.html

111/sol3.py Outdated
if root is None:
return 0

def dfs(node, depth):
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dfs には読み手にとっての情報が少ないので、何か読解の手がかりになる情報を乗せてあげたいです。

111/sol4.py Outdated
Comment on lines +14 to +15
que = deque()
que.append((root, False))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

末尾からpopしているのでstackで良さそうですね。

Suggested change
que = deque()
que.append((root, False))
que = [(root, False)]

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.

stackとして用いる場合には配列(List)を用いるようにしようと思います。

111/sol4.py Outdated
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
node_to_depth = defaultdict(int)
visited_nodes = set()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

キューに is_visited を入れているので、このsetは使っていませんね。一方で、このsetで管理したほうが分かりやすいと思いました。

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.

今回はis_visitedを削除しておきました。
たしかに set管理の方がわかりやすいかもしれません。

111/sol4.py Outdated
Comment on lines +20 to +30
if is_visited:
depth_l = node_to_depth.get(node.left, 0)
depth_r = node_to_depth.get(node.right, 0)
if depth_l == 0 or depth_r == 0:
node_to_depth[node] = max(depth_l, depth_r) + 1
else:
node_to_depth[node] = min(depth_l, depth_r) + 1
else:
que.append((node, True))
que.append((node.left, False))
que.append((node.right, False))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

  • 読むうえではnot visitedの状態から始まるので、先にその場合で分岐してearly continueするのが分かりやすいです
  • node_to_depth にキーが無い=その子ノードが存在しない場合に0を使っているのですが、これをmaxやminと組み合わせているのがpuzzlingです。行数は多くなりますが None の方が分かりやすいです
Suggested change
if is_visited:
depth_l = node_to_depth.get(node.left, 0)
depth_r = node_to_depth.get(node.right, 0)
if depth_l == 0 or depth_r == 0:
node_to_depth[node] = max(depth_l, depth_r) + 1
else:
node_to_depth[node] = min(depth_l, depth_r) + 1
else:
que.append((node, True))
que.append((node.left, False))
que.append((node.right, False))
if not is_visited:
que.append((node, True))
que.append((node.left, False))
que.append((node.right, False))
continue
depth_l = node_to_depth.get(node.left, None)
depth_r = node_to_depth.get(node.right, None)
if depth_l is None and depth_r is None:
node_to_depth[node] = 1
elif depth_l is not None and depth_r is None:
node_to_depth[node] = depth_l + 1
elif depth_l is None and depth_r is not None:
node_to_depth[node] = depth_r + 1
else:
node_to_depth[node] = min(depth_l, depth_r) + 1

ついでにいうと、スタックによって子ノードから先に処理される(node_to_depthに追加される)前提が暗黙にあるのが、読解の上でやや難しいと感じました。

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.

読むうえではnot visitedの状態から始まるので早期 returnすること、depthのロジックが読み手に考えさせるので、もっと簡潔に書くこと、といご指摘採用しました。
自分で気づけるようになることを目指したいです。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants