From a9199bc204eef3f69050bfdc2a1a60e03349110f Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 7 Sep 2025 13:33:02 +0900 Subject: [PATCH 1/5] Solve 103_binary_tree_zigzag_level_order_traversal_medium --- .../dfs.py | 43 ++++++++++++++++ .../step1.py | 48 ++++++++++++++++++ .../step2.py | 49 +++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 103_binary_tree_zigzag_level_order_traversal_medium/dfs.py create mode 100644 103_binary_tree_zigzag_level_order_traversal_medium/step1.py create mode 100644 103_binary_tree_zigzag_level_order_traversal_medium/step2.py diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/dfs.py b/103_binary_tree_zigzag_level_order_traversal_medium/dfs.py new file mode 100644 index 0000000..48c44ab --- /dev/null +++ b/103_binary_tree_zigzag_level_order_traversal_medium/dfs.py @@ -0,0 +1,43 @@ +# +# @lc app=leetcode id=103 lang=python3 +# +# [103] Binary Tree Zigzag Level Order Traversal +# + +# @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 + + +from collections import deque + + +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + if not root: + return [] + nodes_by_level = [] + + def traverse(node: TreeNode, level: int): + while len(nodes_by_level) <= level: + nodes_by_level.append(deque([])) + if level % 2 == 0: + nodes_by_level[level].append(node.val) + else: + nodes_by_level[level].appendleft(node.val) + + if node.left: + traverse(node.left, level + 1) + if node.right: + traverse(node.right, level + 1) + + traverse(root, 0) + + return [list(d) for d in nodes_by_level] + + +# @lc code=end diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/step1.py b/103_binary_tree_zigzag_level_order_traversal_medium/step1.py new file mode 100644 index 0000000..fb287c9 --- /dev/null +++ b/103_binary_tree_zigzag_level_order_traversal_medium/step1.py @@ -0,0 +1,48 @@ +# +# @lc app=leetcode id=103 lang=python3 +# +# [103] Binary Tree Zigzag Level Order Traversal +# + +# @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 zigzagLevelOrder(self, root) -> list[list[int]]: + if not root: + return [] + LEFT_TO_RIGHT = 1 + RIGHT_TO_LEFT = -1 + direction = LEFT_TO_RIGHT + nodes = [root] + zigzag_level_nodes = [] + while nodes: + node_vals = [] + next_level_nodes = [] + while nodes: + node = nodes.pop() + node_vals.append(node.val) + if direction == LEFT_TO_RIGHT: + if node.left: + next_level_nodes.append(node.left) + if node.right: + next_level_nodes.append(node.right) + else: + if node.right: + next_level_nodes.append(node.right) + if node.left: + next_level_nodes.append(node.left) + + zigzag_level_nodes.append(node_vals) + nodes = next_level_nodes + direction *= -1 + return zigzag_level_nodes + + +# @lc code=end diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/step2.py b/103_binary_tree_zigzag_level_order_traversal_medium/step2.py new file mode 100644 index 0000000..159ebb1 --- /dev/null +++ b/103_binary_tree_zigzag_level_order_traversal_medium/step2.py @@ -0,0 +1,49 @@ +# +# @lc app=leetcode id=103 lang=python3 +# +# [103] Binary Tree Zigzag Level Order Traversal +# + +# @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 + + +from collections import deque + + +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + if not root: + return [] + zigzag_level_nodes = [] + nodes = deque([(root, 0)]) + while nodes: + next_nodes = deque([]) + while nodes: + node, level = nodes.popleft() + while len(zigzag_level_nodes) <= level: + zigzag_level_nodes.append(deque([])) + + # left to right + if level % 2 == 0: + zigzag_level_nodes[level].append(node.val) + # right to left + else: + zigzag_level_nodes[level].appendleft(node.val) + + if node.left: + next_nodes.append((node.left, level + 1)) + if node.right: + next_nodes.append((node.right, level + 1)) + + nodes = next_nodes + + return [list(deq) for deq in zigzag_level_nodes] + + +# @lc code=end From e958bac5196aabae5242ff758991a720900e9439 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Tue, 9 Sep 2025 22:23:00 +0900 Subject: [PATCH 2/5] Add initial README structure for binary tree zigzag level order traversal solution --- .../README.md | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 103_binary_tree_zigzag_level_order_traversal_medium/README.md diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/README.md b/103_binary_tree_zigzag_level_order_traversal_medium/README.md new file mode 100644 index 0000000..0e5fe08 --- /dev/null +++ b/103_binary_tree_zigzag_level_order_traversal_medium/README.md @@ -0,0 +1,62 @@ +# 問題へのリンク + + +# 言語 +Python + +# 問題の概要 + + +# 自分の解法 + +## step1 + +```python + +``` + +- 時間計算量:`O(n)` +- 空間計算量:`O(n)` + +## step2 + +```python + +``` + + +- BFSで各レベルごとに走査していくのはstep1と同じ。だが、走査するのは左から順に行い、値の追加だけzigzagになるようにする。 +- +## step3 + +- 点を走査する順番自体を工夫するのか、あるいは値の追加の仕方を工夫するのか。 + - 今回なら、点は普通に左から順に走査していき、値の追加の仕方をzigzagにするのが楽 + +## step4 (FB) + + + +# 別解・模範解答 +## DFS + +- 再帰関数を用いてグラフを走査していく。 +- 各レベルごとのノードのリストを`deque`として保持して、 + - `level` が奇数のときは走査した順、つまりFIFOの順にノードを追加していく。 + - `level` が偶数のときは逆順、つまりLIFOの順にノードを追加していく。 +- 最後に`deque`をリストに変換して返す。 + + + +- 時間計算量:`O(n)` +- 空間計算量:`O(n)` + +# 想定されるフォローアップ質問 + +## CS 基礎 + +## システム設計 + +## その他 + +# 次に解く問題の予告 +- Permutations From e5462d89e78ad60bb4fc4de87a21d49a5e625af2 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Fri, 12 Sep 2025 22:13:42 +0900 Subject: [PATCH 3/5] Add step3 and README --- .../README.md | 156 +++++++++++++++++- .../step3_1.py | 43 +++++ .../step3_2.py | 39 +++++ 3 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 103_binary_tree_zigzag_level_order_traversal_medium/step3_1.py create mode 100644 103_binary_tree_zigzag_level_order_traversal_medium/step3_2.py diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/README.md b/103_binary_tree_zigzag_level_order_traversal_medium/README.md index 0e5fe08..f31fdeb 100644 --- a/103_binary_tree_zigzag_level_order_traversal_medium/README.md +++ b/103_binary_tree_zigzag_level_order_traversal_medium/README.md @@ -12,7 +12,36 @@ Python ## step1 ```python - +class Solution: + def zigzagLevelOrder(self, root) -> list[list[int]]: + if not root: + return [] + LEFT_TO_RIGHT = 1 + RIGHT_TO_LEFT = -1 + direction = LEFT_TO_RIGHT + nodes = [root] + zigzag_level_nodes = [] + while nodes: + node_vals = [] + next_level_nodes = [] + while nodes: + node = nodes.pop() + node_vals.append(node.val) + if direction == LEFT_TO_RIGHT: + if node.left: + next_level_nodes.append(node.left) + if node.right: + next_level_nodes.append(node.right) + else: + if node.right: + next_level_nodes.append(node.right) + if node.left: + next_level_nodes.append(node.left) + + zigzag_level_nodes.append(node_vals) + nodes = next_level_nodes + direction *= -1 + return zigzag_level_nodes ``` - 時間計算量:`O(n)` @@ -21,16 +50,108 @@ Python ## step2 ```python - +from collections import deque + + +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + if not root: + return [] + zigzag_level_nodes = [] + nodes = deque([(root, 0)]) + while nodes: + next_nodes = deque([]) + while nodes: + node, level = nodes.popleft() + while len(zigzag_level_nodes) <= level: + zigzag_level_nodes.append(deque([])) + + # left to right + if level % 2 == 0: + zigzag_level_nodes[level].append(node.val) + # right to left + else: + zigzag_level_nodes[level].appendleft(node.val) + + if node.left: + next_nodes.append((node.left, level + 1)) + if node.right: + next_nodes.append((node.right, level + 1)) + + nodes = next_nodes + + return [list(deq) for deq in zigzag_level_nodes] ``` - BFSで各レベルごとに走査していくのはstep1と同じ。だが、走査するのは左から順に行い、値の追加だけzigzagになるようにする。 -- + ## step3 + +レベルごとに走査を行う方法(`step3_1.py`)。直感的だが、ネストが深くなる。 +リストを再代入していくのもあまり良くないかも。 + +```python +from collections import deque + + +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + zigzag_node_vals: list[deque[int]] = [deque([])] # deque + nodes = [root] + next_level_nodes = [] + level = 0 + + while nodes: + for node in nodes: + if node is None: + continue + next_level_nodes.append(node.left) + next_level_nodes.append(node.right) + # left to right; FIFO + if level % 2 == 0: + zigzag_node_vals[level].append(node.val) + else: # right to left; LIFO + zigzag_node_vals[level].appendleft(node.val) + nodes = next_level_nodes + next_level_nodes = [] + level += 1 + zigzag_node_vals.append(deque([])) + return [list(deq) for deq in zigzag_node_vals] +``` - 点を走査する順番自体を工夫するのか、あるいは値の追加の仕方を工夫するのか。 - 今回なら、点は普通に左から順に走査していき、値の追加の仕方をzigzagにするのが楽 +- 初期値の設定、各ループでの更新のタイミングは統一するのが良い + - 例えば、`next_level_nodes`の初期化をループの外で行い、ループの最後で空にするようにした + - `level`の初期化をループの外で行い、ループの最後でインクリメントするようにした + + + +`nodes`をキューで管理して、ネストを1つ浅くする方法(`step3_2.py`) +```python +from collections import deque + + +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + zigzag_node_vals: list[deque[int]] = [] # deque + nodes_queue = deque([(root, 0)]) + while nodes_queue: + node, level = nodes_queue.popleft() + if node is None: + continue + while len(zigzag_node_vals) <= level: + zigzag_node_vals.append(deque([])) + if level % 2 == 0: # from left to right; FIFO + zigzag_node_vals[level].append(node.val) + else: # from right to left; LIFO + zigzag_node_vals[level].appendleft(node.val) + + nodes_queue.append((node.left, level + 1)) + nodes_queue.append((node.right, level + 1)) + return [list(deq) for deq in zigzag_node_vals] +``` ## step4 (FB) @@ -39,6 +160,34 @@ Python # 別解・模範解答 ## DFS +```python +from collections import deque + + +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + if not root: + return [] + nodes_by_level = [] + + def traverse(node: TreeNode, level: int): + while len(nodes_by_level) <= level: + nodes_by_level.append(deque([])) + if level % 2 == 0: + nodes_by_level[level].append(node.val) + else: + nodes_by_level[level].appendleft(node.val) + + if node.left: + traverse(node.left, level + 1) + if node.right: + traverse(node.right, level + 1) + + traverse(root, 0) + + return [list(d) for d in nodes_by_level] +``` + - 再帰関数を用いてグラフを走査していく。 - 各レベルごとのノードのリストを`deque`として保持して、 - `level` が奇数のときは走査した順、つまりFIFOの順にノードを追加していく。 @@ -46,7 +195,6 @@ Python - 最後に`deque`をリストに変換して返す。 - - 時間計算量:`O(n)` - 空間計算量:`O(n)` diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/step3_1.py b/103_binary_tree_zigzag_level_order_traversal_medium/step3_1.py new file mode 100644 index 0000000..2fe7bb2 --- /dev/null +++ b/103_binary_tree_zigzag_level_order_traversal_medium/step3_1.py @@ -0,0 +1,43 @@ +# +# @lc app=leetcode id=103 lang=python3 +# +# [103] Binary Tree Zigzag Level Order Traversal +# + +# @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 + +from collections import deque + + +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + zigzag_node_vals: list[deque[int]] = [deque([])] # deque + nodes = [root] + next_level_nodes = [] + level = 0 + + while nodes: + for node in nodes: + if node is None: + continue + next_level_nodes.append(node.left) + next_level_nodes.append(node.right) + # left to right; FIFO + if level % 2 == 0: + zigzag_node_vals[level].append(node.val) + else: # right to left; LIFO + zigzag_node_vals[level].appendleft(node.val) + nodes = next_level_nodes + next_level_nodes = [] + level += 1 + zigzag_node_vals.append(deque([])) + return [list(deq) for deq in zigzag_node_vals] + + +# @lc code=end diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/step3_2.py b/103_binary_tree_zigzag_level_order_traversal_medium/step3_2.py new file mode 100644 index 0000000..4490d9f --- /dev/null +++ b/103_binary_tree_zigzag_level_order_traversal_medium/step3_2.py @@ -0,0 +1,39 @@ +# +# @lc app=leetcode id=103 lang=python3 +# +# [103] Binary Tree Zigzag Level Order Traversal +# + +# @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 + + +from collections import deque + + +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + zigzag_node_vals: list[deque[int]] = [] # deque + nodes_queue = deque([(root, 0)]) + while nodes_queue: + node, level = nodes_queue.popleft() + if node is None: + continue + while len(zigzag_node_vals) <= level: + zigzag_node_vals.append(deque([])) + if level % 2 == 0: # from left to right; FIFO + zigzag_node_vals[level].append(node.val) + else: # from right to left; LIFO + zigzag_node_vals[level].appendleft(node.val) + + nodes_queue.append((node.left, level + 1)) + nodes_queue.append((node.right, level + 1)) + return [list(deq) for deq in zigzag_node_vals] + + +# @lc code=end From 4fbf260839d507be81920f4db74e4dd6ed527442 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Fri, 12 Sep 2025 22:25:53 +0900 Subject: [PATCH 4/5] Update README --- .../README.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/README.md b/103_binary_tree_zigzag_level_order_traversal_medium/README.md index f31fdeb..5adee6d 100644 --- a/103_binary_tree_zigzag_level_order_traversal_medium/README.md +++ b/103_binary_tree_zigzag_level_order_traversal_medium/README.md @@ -1,5 +1,5 @@ # 問題へのリンク - +[103. Binary Tree Zigzag Level Order Traversal](https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/) # 言語 Python @@ -198,13 +198,3 @@ class Solution: - 時間計算量:`O(n)` - 空間計算量:`O(n)` -# 想定されるフォローアップ質問 - -## CS 基礎 - -## システム設計 - -## その他 - -# 次に解く問題の予告 -- Permutations From 4faabcb3fd33b47a85f4e430dd81cdde546ca731 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Fri, 12 Sep 2025 22:27:22 +0900 Subject: [PATCH 5/5] Add step3_3.py implementation for zigzag level order traversal using list and reverse --- .../README.md | 34 ++++++++++++++- .../step3_3.py | 43 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 103_binary_tree_zigzag_level_order_traversal_medium/step3_3.py diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/README.md b/103_binary_tree_zigzag_level_order_traversal_medium/README.md index 5adee6d..401eae2 100644 --- a/103_binary_tree_zigzag_level_order_traversal_medium/README.md +++ b/103_binary_tree_zigzag_level_order_traversal_medium/README.md @@ -153,6 +153,39 @@ class Solution: return [list(deq) for deq in zigzag_node_vals] ``` + +`reverse`を使う方法(`step3_3.py`) +```python +class Solution: + def zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + zigzag_level_order_vals: list[list[int]] = [] # deque + nodes = [root] + next_level_nodes = [] + level = 0 + + while True: + zigzag_vals = [] + for node in nodes: + if node is None: + continue + zigzag_vals.append(node.val) + next_level_nodes.append(node.left) + next_level_nodes.append(node.right) + + if not next_level_nodes: + return zigzag_level_order_vals + # align node vals from right to left + if level % 2 == 1: + zigzag_vals.reverse() + zigzag_level_order_vals.append(zigzag_vals) + nodes = next_level_nodes + next_level_nodes = [] + level += 1 +``` +- `deque`を使わずに、普通のリストで値を保持し、`reverse`で並び替える方法 +- levelごとにループを回すので、ネストは深くなるが、どのコードよりもzigzagの処理ががシンプルになる + + ## step4 (FB) @@ -197,4 +230,3 @@ class Solution: - 時間計算量:`O(n)` - 空間計算量:`O(n)` - diff --git a/103_binary_tree_zigzag_level_order_traversal_medium/step3_3.py b/103_binary_tree_zigzag_level_order_traversal_medium/step3_3.py new file mode 100644 index 0000000..67a0d7c --- /dev/null +++ b/103_binary_tree_zigzag_level_order_traversal_medium/step3_3.py @@ -0,0 +1,43 @@ +# +# @lc app=leetcode id=103 lang=python3 +# +# [103] Binary Tree Zigzag Level Order Traversal +# + +# @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 zigzagLevelOrder(self, root: TreeNode | None) -> list[list[int]]: + zigzag_level_order_vals: list[list[int]] = [] # deque + nodes = [root] + next_level_nodes = [] + level = 0 + + while True: + zigzag_vals = [] + for node in nodes: + if node is None: + continue + zigzag_vals.append(node.val) + next_level_nodes.append(node.left) + next_level_nodes.append(node.right) + + if not next_level_nodes: + return zigzag_level_order_vals + # align node vals from right to left + if level % 2 == 1: + zigzag_vals.reverse() + zigzag_level_order_vals.append(zigzag_vals) + nodes = next_level_nodes + next_level_nodes = [] + level += 1 + + +# @lc code=end