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
41 changes: 41 additions & 0 deletions arai60/minimum-depth-of-binary-tree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## 考察
- 初見の問題
- 昨日の問題が maximum depth だったのに対して minimum depth
- 方針
- DFS
- 帰りがけ
- left subtreeとright subtreeのdepthのminを取って1を足して返却
- 再帰の深さについて考える必要
- 最大10^5のため、デフォルトのPythonの環境では厳しい(一応LeetCode上ならOK)
- 帰りがけDFSを非再帰で書くのはつらい
- 行きがけ
- 全探索しながらleafのときに答えを更新
- BFS
- level順に見ていくので、leafが見つかったら答えをreturnしてOK
- 上記を考慮して、Step1はBFSでやる
- あとは実装

## Step1
- BFSで実装
- nodeがNoneのときにはキューに入れない実装もできるが、複雑度(if文)が2つ増えるためこちらの書き方を選択
- time: O(n), space: O(n)

## Step2
- 帰りがけDFSと行きがけDFSでも書いてみる
- `step2_postorder_dfs.py`
- `step2_preorder_dfs.py`
- 実装のしやすさでは再帰DFS
- 他の人のPRを検索してみる
- BFSはキューを2つ作る書き方も主流みたい
- https://github.com/fhiyo/leetcode/pull/24#discussion_r1648682841
- この書き方はtorusさんのword ladderでのbidirectional bfsの解法のところでも見た
- 前から順番に取り出せればいいのでキューである必要はなさそう
- float('inf')について
- https://github.com/fhiyo/leetcode/pull/24#discussion_r1648673169
- is と == の違い
- https://github.com/sakupan102/arai60-practice/pull/23#discussion_r1591177498

## Step3
- 1回目: 1m16s
- 2回目: 1m03s
- 3回目: 1m01s
18 changes: 18 additions & 0 deletions arai60/minimum-depth-of-binary-tree/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# 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:
nodes_to_visit = deque([(root, 1)])
while nodes_to_visit:
node, depth = nodes_to_visit.popleft()
if not node: continue
if not node.left and not node.right:
return depth
nodes_to_visit.append((node.left, depth + 1))
nodes_to_visit.append((node.right, depth + 1))

return 0
20 changes: 20 additions & 0 deletions arai60/minimum-depth-of-binary-tree/step2_postorder_dfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 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 not root:
return 0
if not root.left and not root.right:
return 1

min_depth = math.inf
if root.left:
min_depth = min(min_depth, self.minDepth(root.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.

見やすさのために書いているかもしれませんが、ここはmin_depth = self.minDepth(root.left)でも通りそうですね。

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.

たしかにそれでもいいですね。
自分は関数型言語でいうところのfoldのイメージで書いてました。
単位元で初期化して、二項関数で一つにまとめていくイメージです。

if root.right:
min_depth = min(min_depth, self.minDepth(root.right))

return min_depth + 1
24 changes: 24 additions & 0 deletions arai60/minimum-depth-of-binary-tree/step2_preorder_dfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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 not root:
return 0

min_depth = math.inf
nodes_to_visit = [(root, 1)]
while nodes_to_visit:
node, depth = nodes_to_visit.pop()
if not node.left and not node.right:
min_depth = min(min_depth, depth)

if 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
Owner Author

Choose a reason for hiding this comment

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

ああ、たしかにそうですね。そこまで気が回っていませんでした、ありがとうございます。

nodes_to_visit.append((node.left, depth + 1))
if node.right:
nodes_to_visit.append((node.right, depth + 1))

return min_depth
17 changes: 17 additions & 0 deletions arai60/minimum-depth-of-binary-tree/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 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:
nodes_to_visit = deque([(root, 1)])
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

好みの問題かもしれませんが、nodes_to_visitよりも、queueの中身をより反映させるために、nodes_and_depthに自分ならするかもしれません。

while nodes_to_visit:
node, depth = nodes_to_visit.popleft()
if not node: continue
if not node.left and not node.right:
return depth
nodes_to_visit.append((node.left, depth + 1))
nodes_to_visit.append((node.right, depth + 1))
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.

rootがNoneのときにしかここに到達しない旨のコメントはあってもいいかもなと思いました。
nodeがNoneのとき、leafのとき、内部節点のときそれぞれの場合で処理を考えないとそれが分からず、分からないと0を返して本当にいいんだっけ?と不安になるからです。

Copy link
Copy Markdown
Owner Author

@kazukiii kazukiii Jul 8, 2024

Choose a reason for hiding this comment

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

ありがとうございます。おっしゃる通りだと思いました。
もしくは、先頭でrootがNoneの場合を弾いた方が読みやすいでしょうか?

class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        nodes_to_visit = deque([(root, 1)])
        while nodes_to_visit:
            node, depth = nodes_to_visit.popleft()
            if not node: continue
            if not node.left and not node.right:
                return depth
            nodes_to_visit.append((node.left, depth + 1))
            nodes_to_visit.append((node.right, depth + 1))
        
        raise ValueError("unreachable")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

コメントにするか先に弾くかは趣味の範囲な気が自分はしました。どちらも読みやすいと思います!