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
32 changes: 32 additions & 0 deletions problems/102.binary-tree-level-order-traversal/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## step1
- 読解の自信がない
- rootからのstepごとにNodeのvalueを配列に入れて返せば良いと理解した
- その際に左から右に返す
- 幅優先探索で解けば良さそう
- 特に苦労なく書けた
- 方針として毎回level毎に新しくfrontierを作るか、levelもfrontierに入れて管理するか迷ったが毎回level毎に作った方がわかりやすそうだと思ったので現在の実装にした
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

step1の段階なのに視野が広く取れているなーと感心しました(自分は基本的にこの段階では解くので精一杯なので)。

- `while True`が自分の中でだいぶ抵抗があった
- 今回の主役はfrontierにしたいのだが、`while frontier`とすると毎回末尾でfrontierが空かどうかを判定して次の階層にいく必要が出てきそうなのでやめた
- 処理のまとまり的にも1つの階層を処理して次の階層が終わるまで処理するという2重のloopっぽい動きと捉えたので1つのwhileに頑張ってまとめようとしなかった

## step2
- 時間計算量はO(N),空間計算量もO(N)だと思う
- 答えを1行ずつ出していいなら空間計算量はO(logN)になると思う
- 他の人のコードを読む
- https://github.com/Shoichifunyu/shofun/pull/20
- `ret`が気になって調べたが最終的に返す値を一時的に入れておく変数でC/C++系でよく使われてたとのこと
- 自分もこの問題の時に`result`と書こうとしたので気持ちは分かるが少しでも意味をつけようと思って`level_order_values`とした
- 関数名をつける時に`build`も思いつけるようにしておきたいと思った
- https://github.com/mamo3gr/arai60/pull/25/changes
- 再帰でも書けるのかなと一瞬思ったが、最後に配列で返す必要があって難しそうだなと思ったがstep2を見てわかりやすかったし短くかけてていいなと思った
- 階層ごとに処理をする場合はwhileでpopしなくてもforでも良いことに気づいた
- `if だと「インデックスが範囲外になる場合のずれは高々1だけのはずだ」という、外部のロジックへの依存・信頼が必要になり、読むときも俯瞰的に読まないといけません。while であれば、「配列長が足りなければ足りるまで伸ばす」というシンプルで独立したロジックとして完結しているため、局所的にパッと見たときの安心感があります。`確かに外部のロジックに依存して動くよりは独立して動いた方がいいと思った。こういう観点でも考えられるようにしたい。
- https://github.com/plushn/SWE-Arai60/pull/26
- `itertools.chain`初めて知った
- https://docs.python.org/ja/3/library/itertools.html#itertools.chain
- `current_level`の命名がいいなと思ったfrontierよりその階層のものという情報が足される
- step2は再帰で書いてみる

## step3
- step1と同じやり方でforとwhile Trueの部分を修正して書いた

43 changes: 43 additions & 0 deletions problems/102.binary-tree-level-order-traversal/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#
# @lc app=leetcode id=102 lang=python3
#
# [102] Binary Tree 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
import collections


class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
level_order_values = []
if root is None:
return level_order_values
frontier = collections.deque()
frontier.append(root)

while True:
order_values = []
next_frontier = collections.deque()
while frontier:
node = frontier.popleft()
order_values.append(node.val)
if node.left:
next_frontier.append(node.left)
if node.right:
next_frontier.append(node.right)
level_order_values.append(order_values)
if not next_frontier:
break
frontier = next_frontier

return level_order_values


# @lc code=end
34 changes: 34 additions & 0 deletions problems/102.binary-tree-level-order-traversal/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# @lc app=leetcode id=102 lang=python3
#
# [102] Binary Tree 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 levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
level_order_values = []
if root is None:
return level_order_values
Comment on lines +16 to +18
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

些末ですが…

level_order_values を空のリストとして初期化します。rootNone なら level_order_values を返します。さて戻り値はなんでしょう。」というマイクロ謎解きが発生するので、ダイレクトに空のリストを返すほうが好みです。root is None なら、そもそも level_order_values という変数の存在自体を知る必要がありません。

Suggested change
level_order_values = []
if root is None:
return level_order_values
if root is None:
return []
level_order_values = []


def traverse(node: TreeNode, level: int):
while level >= len(level_order_values):
level_order_values.append([])

level_order_values[level].append(node.val)
if node.left:
traverse(node.left, level + 1)
if node.right:
traverse(node.right, level + 1)

traverse(root, 0)
return level_order_values


# @lc code=end
37 changes: 37 additions & 0 deletions problems/102.binary-tree-level-order-traversal/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# @lc app=leetcode id=102 lang=python3
#
# [102] Binary Tree 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 levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
level_order_values = []
if root is None:
return level_order_values

current_level = [root]
while current_level:
current_values = []
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

細かいですが、current_ と対応する next_values は登場せず、ライフタイムもこのループ内だけなので values でも良さそうに感じました。current_level と関係があることを示唆する current_level_values でもいいかもしれません。

next_level = []
for current in current_level:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ここは現在の (current) というより、ノードであるという情報のほうが重要に思いました。

Suggested change
for current in current_level:
for node in current_level:

current_values.append(current.val)
if current.left:
next_level.append(current.left)
if current.right:
next_level.append(current.right)

level_order_values.append(current_values)
current_level = next_level

return level_order_values


# @lc code=end