diff --git a/111/111.md b/111/111.md new file mode 100644 index 0000000..067e156 --- /dev/null +++ b/111/111.md @@ -0,0 +1,182 @@ +## 何も見ずに解いてみる + +```python +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + queue = deque([(root, 1)]) + while queue: + node, depth = queue.popleft() + if not node.left and not node.right: + return depth + if node.left: + queue.append((node.left, depth + 1)) + if node.right: + queue.append((node.right, depth + 1)) +``` + +## 色々調べてみる + +https://github.com/SuperHotDogCat/coding-interview/pull/36/files +https://github.com/hayashi-ay/leetcode/pull/26/files +https://github.com/shintaro1993/arai60/pull/26/files +https://github.com/tokuhirat/LeetCode/pull/22/files + +tokuhiratさんが書いていた帰りがけにdepthを伝えるstackのDFSみたいな書き方を試してみた。 + +```python +from dataclasses import dataclass + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + + @dataclass + class StackEntry: + node: TreeNode + parent: Optional[TreeNode] + depth: int + explored: bool = False + + stack = [StackEntry(root, None, 1)] + while stack: + entry = stack[-1] + if not entry.explored: + if not entry.node.left and not entry.node.right: + entry.explored = True + continue + if entry.node.left: + stack.append(StackEntry(entry.node.left, entry.node, entry.depth + 1)) + if entry.node.right: + stack.append(StackEntry(entry.node.right, entry.node, entry.depth + 1)) + else: # If stack[-1] is explored + stack.pop() + if not entry.parent: + return entry.depth + if stack[-1].parent == entry.parent: # If stack[-1] is sibling + sibling_entry = stack.pop() + if not sibling_entry.explored: + stack.append(entry) + stack.append(sibling_entry) + continue + parent_entry = stack[-1] + parent_entry.depth = min(entry.depth, sibling_entry.depth) + parent_entry.explored = True + else: # If stack[-1] is parent + parent_entry = stack[-1] + parent_entry.depth = entry.depth + parent_entry.explored = True +``` + +こんな感じで常に直前のstackが親になるようにすることもできそう +is_leftはLiteral["left", "right"]とかにした方がわかりやすいかな? +math.infを使うのは分かりづらそう、Noneで初期化・分岐した方が良いか + +```python +from dataclasses import dataclass +from math import inf, isinf + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + + @dataclass + class StackEntry: + node: TreeNode + parent: Optional[TreeNode] + is_left: bool + depth: int + min_depth: int = math.inf + + stack = [StackEntry(root, None, 1, False)] + while True: + entry = stack[-1] + if isinf(entry.min_depth): + if not entry.node.left and not entry.node.right: + entry.min_depth = entry.depth + continue + if entry.node.left: + stack.append(StackEntry(entry.node.left, entry.node, True, entry.depth + 1)) + elif entry.node.right: + stack.append(StackEntry(entry.node.right, entry.node, False, entry.depth + 1)) + else: + stack.pop() + if not stack: # If the entry is the root + return entry.min_depth + parent_entry = stack[-1] + parent_entry.min_depth = min(entry.min_depth, parent_entry.min_depth) + if entry.is_left and parent_entry.node.right: + stack.append(StackEntry(parent_entry.node.right, parent_entry.node, False, parent_entry.depth + 1)) +``` + +もっとわかりやすく書くならこんな感じ?逆にわかりにくいかも + +```python +from dataclasses import dataclass + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + + @dataclass + class StackEntry: + node: TreeNode + parent: Optional[TreeNode] + pos_to_parent: Optional[Literal["left", "right"]] + depth: int + def __post_init__(self): + self.children_min_depths = {} + if self.node.left: + self.children_min_depths["left"] = None + if self.node.right: + self.children_min_depths["right"] = None + + stack = [StackEntry(root, None, None, 1)] + while True: + entry = stack[-1] + if "left" in entry.children_min_depths and entry.children_min_depths["left"] is None: + stack.append(StackEntry( + node=entry.node.left, + parent=entry.node, + pos_to_parent="left", + depth=entry.depth + 1, + )) + continue + if "right" in entry.children_min_depths and entry.children_min_depths["right"] is None: + stack.append(StackEntry( + node=entry.node.right, + parent=entry.node, + pos_to_parent="right", + depth=entry.depth + 1, + )) + continue + min_depth = min(entry.children_min_depths.values()) if entry.node.left or entry.node.right else entry.depth + stack.pop() + if not stack: + return min_depth + stack[-1].children_min_depths[entry.pos_to_parent] = min_depth +``` + +## 最終コード + +```python +from collections import deque + +class Solution: + def minDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + queue = deque([(root, 1)]) + while queue: + node, depth = queue.popleft() + if not node.left and not node.right: + return depth + if node.left: + queue.append((node.left, depth + 1)) + if node.right: + queue.append((node.right, depth + 1)) +```