From ce6db9d9c7aff521f662ffbda0cd2a8bbdfe82c2 Mon Sep 17 00:00:00 2001 From: nittoco <166355467+nittoco@users.noreply.github.com> Date: Thu, 28 Nov 2024 00:41:03 +0900 Subject: [PATCH] Create 111. Minimum Depth of Binary Tree.md --- 111. Minimum Depth of Binary Tree.md | 233 +++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 111. Minimum Depth of Binary Tree.md diff --git a/111. Minimum Depth of Binary Tree.md b/111. Minimum Depth of Binary Tree.md new file mode 100644 index 0000000..515ce80 --- /dev/null +++ b/111. Minimum Depth of Binary Tree.md @@ -0,0 +1,233 @@ +### Step1 + +- 最初、こう間違えた + - 入力が空の考慮をしなかったのはダメだったが、空の時の出力が0というのもなんか微妙だな + +```python +class Solution: + def minDepth(self, node: Optional[TreeNode]) -> int: + if not node: + return inf + if not node.left and not node.right: + return 1 + return min(self.minDepth(node.left), self.minDepth(node.right)) + 1 +``` + +- infはあんまり使いたくないなあ + - float型が出るのと、意図がわかりにくいかも +- 思ったよりちょっとだけややこしくなった +- 再帰の回数は、枝の数だけある。 + - 10^5が最大で、環境によっては超えるかも + +```python +class Solution: + def minDepth(self, node: Optional[TreeNode]) -> int: + if not node: + return 0 + if not node.left and not node.right: + return 1 + if not node.right: + return self.minDepth(node.left) + 1 + if not node.left: + return self.minDepth(node.right) + 1 + return min(self.minDepth(node.left), self.minDepth(node.right)) + 1 +``` + +- ループにするため、まずは末尾再帰(ぽい形)に + - 別にnot_reached_leafとかで変数も作れるけど、まあinfで妥協 + +```python + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + depth_min = inf + + def min_depth_helper(node, depth): + nonlocal depth_min + if not node: + return + if not node.left and not node.right: + depth_min = min(depth_min, depth) + min_depth_helper(node.left, depth + 1) + min_depth_helper(node.right, depth + 1) + + min_depth_helper(root, 1) + return depth_min +``` + +- 上の処理をループに + - leafの判定は切り出した方がわかりやすいかも +- タプルの中身2つだとdataclass作るまでもないかなあ + +```python +class Solution: + def is_leaf(self, node: [TreeNode]) -> bool: + return not node.left and not node.right + + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + stack = [(root, 1)] + result = inf + while stack: + node, depth = stack.pop() + if not node: + continue + if self.is_leaf(node): + result = min(depth, result) + continue + stack.append((node.left, depth + 1)) + stack.append((node.right, depth + 1)) + return result + +``` + +- BFSでも書いてみる + +```python + +class Solution: + def is_leaf(self, node: [TreeNode]) -> bool: + return not node.left and not node.right + + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + current_level = [(root, 1)] + result = inf + while True: + if not current_level: + return result + next_level = [] + for node, depth in current_level: + if not node: + continue + if self.is_leaf(node): + result = min(depth, result) + next_level.append((node.left, depth + 1)) + next_level.append((node.right, depth + 1)) + current_level = next_level +``` + +### Step2 + +https://github.com/seal-azarashi/leetcode/pull/21 + +- BFSはlevel別に配列管理した方が好み +- BFSでループが回る場合の処理を書くなら、無限ループの方が意図がわかりやすい、確かに + +https://github.com/goto-untrapped/Arai60/pull/46 + +- DFSだったら枝狩りできるの気がつかなかった〜 + - こういうの自分気づかないがち +- while Trueを嫌がるコメント、他の方のでも見たことあるが、個人的に賛成はできない。while(条件)の条件部分を、if not 条件 breakって中に書けば同じなので + - ループの停止が決定不能問題だから、ループそのもの自体そもそも気をつけようというのはあるかも +- infをINITIALIZEDにするのはなるほどと思ったが、それなら別変数で定義する方がわかりやすいかもなあ +- rootがnullの判定をやめて最後にreturn 0するのはあまり好みではない。return 0がなんの時なのかがわかりにくいため + +https://github.com/Ryotaro25/leetcode_first60/pull/24 + +- nullの場合を探索しない再帰も実装してもいいかも + +https://github.com/TORUS0818/leetcode/pull/24 + +- 単位元が0のminをカスタム定義は、中身がわけわかんなくなるかも? + +https://github.com/hroc135/leetcode/pull/21/files + +- BFS、よく考えたらdepthはタプルに入れなくてもdepth+=1でよかった +- depth += 1をループの最初に書くか、最後に書くか、迷う + - メインの処理で、最初にないと読んでて不安になる? + - でも重要な変数が最初にいきなり変わるのは混乱する? + - う〜む難しい +- 償却計算量、CSライザップでやったが、ちゃんとした式を追ってなかったので勉強になった + +https://github.com/Yoshiki-Iwasa/Arai60/pull/25/files + +- .leftと.rightをループで回してもいいのか、迷う + +- 枝刈りBFSを書いてみる +- 試しに今回はnullは突っ込まないように + +```python + +class Solution: + def is_leaf(self, node: [TreeNode]) -> bool: + return not node.left and not node.right + + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + current_level_nodes = [root] + depth = 0 + while True: + depth += 1 + next_level_nodes = [] + for node in current_level_nodes: + if self.is_leaf(node): + return depth + if node.left: + next_level_nodes.append(node.left) + if node.right: + next_level_nodes.append(node.right) + current_level_nodes = next_level_nodes +``` + +- infの代わりに、まだ見てないかを別変数で定義 + - やりすぎ? + +```python + +class Solution: + def is_leaf(self, node: [TreeNode]) -> bool: + return not node.left and not node.right + + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + node_with_depth = [(root, 1)] + reached_leaf_so_far = False + result = None + while node_with_depth: + node, depth = node_with_depth.pop() + if not node: + continue + if self.is_leaf(node): + if reached_leaf_so_far and depth >= result: + continue + result = depth + reached_leaf_so_far = True + node_with_depth.append((node.right, depth + 1)) + node_with_depth.append((node.left, depth + 1)) + return result +``` + +## Step3 + +- BFSが自然かなあ + +```python + +class Solution: + def is_leaf(self, node: [TreeNode]) -> bool: + return not node.left and not node.right + + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + current_level_nodes = [root] + depth = 0 + while True: + depth += 1 + next_level_nodes = [] + for node in current_level_nodes: + if not node: + continue + if self.is_leaf(node): + return depth + next_level_nodes.append(node.left) + next_level_nodes.append(node.right) + current_level_nodes = next_level_nodes +```