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
48 changes: 48 additions & 0 deletions 103-Binary-Tree-Zigzag-Level-Order-Traversal/note.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# 103. Binary Tree Zigzag Level Order Traversal

https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/description/

## step1(まず通す)

node を取り出す時に値をチェックすると反転の扱いが面倒そうと考えて、詰める時にチェックするようにした。

フラグを用意して切り替えることも考えたが、2階層セットで書けば同じことの繰り返しなのでコードの重複部分が増える代わりに考えることが減ると思って書いた。

## step2(整形&他の人のコードを読む)

実際書いてみると、奇数階層と偶数階層で異なるのは右の子を先に見るか左の子を先に見るかだけなのでここをフラグ化して関数に切り出してみる。

フラグによる切り替え部分は以下のようにも書ける。ちょっとパズル的で読みづらいかもしれない。

```python
if left_first:
if node.left is not None:
next_level_values.append(node.left.val)
next_level_nodes.append(node.left)

if node.right is not None:
next_level_values.append(node.right.val)
next_level_nodes.append(node.right)

if not left_first:
if node.left is not None:
next_level_values.append(node.left.val)
next_level_nodes.append(node.left)
```

### 他の方のコード

- https://github.com/naoto-iwase/leetcode/pull/31/changes#diff-18873955c02f8e2268cf8385696e9d0aa7cce7bd5e4d5059818cb2903515da83R15
- 「levelごとのvaluesは、level内では常にleft to rightで一旦貯めていき、複数レベルのリストに格納する直前に反転するかどうか決めたらいい。」
- この単純な事実に気づいていなかった。「node を取り出す時に値をチェックすると反転の扱いが面倒そう」と思い込んでいたが実際にはそうではなかった。
- ただしリストのコピーは発生する。
- とはいっても、Python で高速化してもしょうがないし面はあるので、Python だけで書くなら読みやすさ的にこれがよさそう。

## step3(10分以内にさっとかける \* 3回)

zigzag じゃないバージョン(102: 前回の PR で解いた)とほぼ同じで、values を収集した後に二回に一回反転する実装。

[sorted は list を返す](https://docs.python.org/ja/3/library/functions.html#sorted)が、[reversed は要素を逆順に取り出すイテレータを返す](https://docs.python.org/ja/3/library/functions.html#reversed)ので sorted のノリで
`values_by_level.append(reversed(values))` と書くとエラーになる。

sequence.reverse() は in-place で逆順にして None を返すので `values_by_level.append(values.reverse())` も書けない。
52 changes: 52 additions & 0 deletions 103-Binary-Tree-Zigzag-Level-Order-Traversal/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from typing import Optional


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: Optional[TreeNode]) -> list[list[int]]:
if root is None:
return []

values_by_level: list[list[int]] = [[root.val]]
nodes: list[TreeNode] = [root]
# 2階層ごとに同じことを繰り返すので、2階層セットでループを回す
while nodes:
# まず次のレベルを右から左へ見る
next_level_values: list[int] = []
next_level_nodes: list[TreeNode] = []
while nodes:
node = nodes.pop()
if node.right is not None:
next_level_values.append(node.right.val)
next_level_nodes.append(node.right)
if node.left is not None:
next_level_values.append(node.left.val)
next_level_nodes.append(node.left)

if next_level_values:
values_by_level.append(next_level_values)
nodes = next_level_nodes

# 次に、左から右へ
next_level_values = []
next_level_nodes = []
while nodes:
node = nodes.pop()
if node.left is not None:
next_level_values.append(node.left.val)
next_level_nodes.append(node.left)
if node.right is not None:
next_level_values.append(node.right.val)
next_level_nodes.append(node.right)

if next_level_values:
values_by_level.append(next_level_values)
nodes = next_level_nodes

return values_by_level
52 changes: 52 additions & 0 deletions 103-Binary-Tree-Zigzag-Level-Order-Traversal/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from typing import Optional


class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right


class Solution:
def traverse_next_level(
self, nodes: list[TreeNode], left_first: bool
) -> tuple[list[int], list[TreeNode]]:
next_level_values: list[int] = []
next_level_nodes: list[TreeNode] = []
while nodes:
node = nodes.pop()
if left_first:
if node.left is not None:
next_level_values.append(node.left.val)
next_level_nodes.append(node.left)
if node.right is not None:
next_level_values.append(node.right.val)
next_level_nodes.append(node.right)
else:
if node.right is not None:
next_level_values.append(node.right.val)
next_level_nodes.append(node.right)
if node.left is not None:
next_level_values.append(node.left.val)
next_level_nodes.append(node.left)

return next_level_values, next_level_nodes

def zigzagLevelOrder(self, root: Optional[TreeNode]) -> list[list[int]]:
if root is None:
return []

values_by_level: list[list[int]] = [[root.val]]
nodes: list[TreeNode] = [root]
left_first = False # 根の直下は右から見る
while nodes:
next_level_values, next_level_nodes = self.traverse_next_level(
nodes, left_first
)
if next_level_values:
values_by_level.append(next_level_values)
nodes = next_level_nodes
left_first = not left_first

return values_by_level
36 changes: 36 additions & 0 deletions 103-Binary-Tree-Zigzag-Level-Order-Traversal/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import Optional


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: Optional[TreeNode]) -> list[list[int]]:
if root is None:
return []

values_by_level = []
nodes = [root]
is_left_to_right = True
while nodes:
values = []
next_level = []
for node in nodes:
values.append(node.val)
if node.left is not None:
next_level.append(node.left)
if node.right is not None:
next_level.append(node.right)

if not is_left_to_right:
values.reverse()
values_by_level.append(values)

nodes = next_level
is_left_to_right = not is_left_to_right

return values_by_level