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
51 changes: 51 additions & 0 deletions problems/111.minimum-depth-of-binary-tree/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
## step1
- 最小の深さを求める
- 短い箇所を見つけるので幅優先探索の方がいい
- 片方だけNoneを見つけてWAを出してしまったので要件をしっかり確認するようにしたい
- 時間計算量はO(N)
- 空間計算量はO(logN)だと思う
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

木が平衡だった場合、深さが最小となる葉ノードを見つけたときに、直前の深さのすべてのノードが配列に含まれると思います。深さ log N のノードの数は約 N / 2 個、その親の数は N / 4 個となりますので、空間計算量は O(N) になると思います。


## step2
- 他の人のコードを見てみる
- https://github.com/Yuto729/LeetCode_arai60/pull/27
- `raise AssertionError("unreachable")`returnせずにwhileループを抜けたときに処理が何もないのは気持ちが悪いと思ったので一応入れておいた
- この気持ち悪さは自分の中にあった
- `is_leaf`は端的に状況を表していていいと思った
- 再帰でも書けるのは思いつかなかった
- じっくり見てやっと分かるくらい
- どのくらいStackに積まれるのかの見積もりが難しいが多分木の深さ
- 下記のような状態の時に無駄に探索されているように思った
- 結局全てのパターンで探索されているので無駄が多いと思った
```
root
/ \
L R
/ \
L (leaf)
/
L
/
L
/
(leaf)
```
- https://github.com/mamo3gr/arai60/pull/20/changes
- `入出力が合うかのガチャをやり始めると意識が離れてしまう。`これは難しい問題をバグらせた時についやってしまう。実務だと使えない方法なのでしないようにしたい。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

実務でもテストを書くとできてしまうんですよね。

[fyi]

ジャッジシステムでレバガチャをしない

https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.ofzx0kw1dsrd

- 再帰のメリット、デメリットがまとめられていてよかった。分割統治法の意識があれば少し苦手意識が薄れそう。
- `next_to_visitは辞書やhashの名前のような印象を受けました。`dict以外でxx_to_xxの変数名をつけないように意識づけたい
- https://github.com/plushn/SWE-Arai60/pull/22/changes
- `これも考慮する場合1つはmin_depth = float("inf")とすれば常に正しく動きます。もう一つは、想定を超える入力が来たときにはエラーを出して止めたりロガーで警告を出すなどのアプローチも考えられます。`後半の選択肢は持っていなかったので覚えておきたい。自分が書いたコードが部分的に変更される可能性を考えて問題が生じそうであれば何らかの形で通知する機能を作る選択肢を持っておく。
- https://github.com/naoto-iwase/leetcode/pull/21/changes
- `これは私の趣味の問題かと思いますが、queue に複数のレベルのものが入るのはあまり好きではないです。`これは同じ感覚があり、forで全て見て次のものは別の変数にした
- https://github.com/nanae772/leetcode-arai60/pull/22/changes
- nodeとdepthを一緒に管理する方法も選択肢にあったが思い返すとメリットデメリットまでしっかり比較せずに、慣れてそうな方法で書いてしまった
- 一緒に更新するメリットはdepthの更新タイミングがとてもしっくりくること?
- デメリットは配列の中でnodeとdepthを管理するので少し構造が複雑になること
- 個人的にはちょうどどっちでも良いくらいだと思った

- 再帰でも練習する


## step3
- depthとnodeとpairで管理する方法でも書いた

36 changes: 36 additions & 0 deletions problems/111.minimum-depth-of-binary-tree/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#
# @lc app=leetcode id=111 lang=python3
#
# [111] Minimum Depth of Binary Tree
#

# @lc code=start
# 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 = 1

to_visit = [root]

while to_visit:
next_to_visit = []
for node in to_visit:
if node.left is None and node.right is None:
return depth
if node.left is not None:
next_to_visit.append(node.left)
if node.right is not None:
next_to_visit.append(node.right)

to_visit = next_to_visit
depth += 1


# @lc code=end
32 changes: 32 additions & 0 deletions problems/111.minimum-depth-of-binary-tree/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# @lc app=leetcode id=111 lang=python3
#
# [111] Minimum Depth of Binary Tree
#

# @lc code=start
# 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 min_depth_helper(root: TreeNode) -> int:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

minDepth のヘルパーであることはまあ自明なので、自分なら

Suggested change
def min_depth_helper(root: TreeNode) -> int:
def helper(root: TreeNode) -> int:

とします。むしろヘルパー関数を書かず、minDepth 自体で再帰しそうです(引数も戻り値も、親関数と変わらないので)。

if root.left is None and root.right is None:
return 1
if root.left is None:
return min_depth_helper(root.right) + 1
if root.right is None:
return min_depth_helper(root.left) + 1

return min(min_depth_helper(root.left), min_depth_helper(root.right)) + 1

return min_depth_helper(root)


# @lc code=end
40 changes: 40 additions & 0 deletions problems/111.minimum-depth-of-binary-tree/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#
# @lc app=leetcode id=111 lang=python3
#
# [111] Minimum Depth of Binary Tree
#

# @lc code=start
# 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
import collections


class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if root is None:
return 0

frontier = collections.deque([(root, 1)])
while frontier:

def is_leaf(node: TreeNode) -> bool:
return node.left is None and node.right is None

node, depth = frontier.popleft()
if is_leaf(node):
return depth
Comment on lines +21 to +30
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
frontier = collections.deque([(root, 1)])
while frontier:
def is_leaf(node: TreeNode) -> bool:
return node.left is None and node.right is None
node, depth = frontier.popleft()
if is_leaf(node):
return depth
def is_leaf(node: TreeNode) -> bool:
return node.left is None and node.right is None
frontier = collections.deque([(root, 1)])
while frontier:
node, depth = frontier.popleft()
if is_leaf(node):
return depth

自分なら、これくらいシンプルなら関数ではなくbooleanにします。

Suggested change
frontier = collections.deque([(root, 1)])
while frontier:
def is_leaf(node: TreeNode) -> bool:
return node.left is None and node.right is None
node, depth = frontier.popleft()
if is_leaf(node):
return depth
frontier = collections.deque([(root, 1)])
while frontier:
node, depth = frontier.popleft()
is_leaf = node.left is None and node.right is None
if is_leaf:
return depth


if node.left is not None:
frontier.append((node.left, depth + 1))
if node.right is not None:
frontier.append((node.right, depth + 1))

raise AssertionError("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.

[nits]
何が起きたか、だけでなく、どうしたらいいか、これを見たユーザーに次のアクションを指示できると良いと思いました。



# @lc code=end