Skip to content

102.binary tree level order traversal#25

Open
tom4649 wants to merge 5 commits intomainfrom
102.Binary-Tree-Level-Order-Traversal
Open

102.binary tree level order traversal#25
tom4649 wants to merge 5 commits intomainfrom
102.Binary-Tree-Level-Order-Traversal

Conversation

@tom4649
Copy link
Copy Markdown
Owner

@tom4649 tom4649 commented Mar 16, 2026

- 空間計算量 O(n)+O(h)

- https://github.com/mamo3gr/arai60/blob/102_binary-tree-level-order-traversal/102_binary-tree-level-order-traversal/step2.py
- 行きがけ順の再帰
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これ、素直に対応するループに直せますか。再帰呼ぶかわりにスタックにやることを積んで dfs にするということです。(再帰とループの変形をすること自体が選択として見えているかが気にかかりました。)

再帰は制限が多いので。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.uvguf4c3q02d
再帰をループに
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.deivkzaqvetb

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

新しく書きました。pythonのsys.setrecursionlimitなど知らなかったので勉強になりました。
https://docs.python.org/3/library/sys.html#sys.setrecursionlimit

@tom4649 tom4649 force-pushed the 102.Binary-Tree-Level-Order-Traversal branch from a04d99e to a37e99f Compare March 17, 2026 21:22
102/sol1.py Outdated
Comment on lines +13 to +20
if len(left_level_order) < len(right_level_order):
left_level_order.extend(
[[] for _ in range(len(right_level_order) - len(left_level_order))]
)
else:
right_level_order.extend(
[[] for _ in range(len(left_level_order) - len(right_level_order))]
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

何をやりたいのか分かりづらいので、サブルーチンにして説明的な名前を付けると良いと思いました。List[List[int]] の長さを揃えたいんですよね。

102/sol1.py Outdated
Comment on lines +22 to +23
for i in range(len(left_level_order)):
merged_level_order.append(left_level_order[i] + right_level_order[i])
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

長さの違うlist同士を処理するなら、itertools.zip_longest が使えそうです。
https://docs.python.org/3/library/itertools.html#itertools.zip_longest

Suggested change
for i in range(len(left_level_order)):
merged_level_order.append(left_level_order[i] + right_level_order[i])
for left, right in itertools.zip_longest(left_level_order, right_level_order, fillvalue=[]):
merged_level_order.append(left + right)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

itertools.zip_longest 知らなかったです。勉強になりました。

102/sol2.py Outdated
def levelOrder(self, root: Optional["TreeNode"]) -> List[List[int]]:
level_order = []

def add_value_by_level(node, 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.

add ではなくて append がより正確に思いました。また、append先になる level_order も引数に取ったほうが、関数呼び出しのパラメータを見て何をするのか分かりやすそうに思いました。

102/sol2_loop.py Outdated
level_order = []
if root is None:
return level_order
children_pushed = deque([(0, root)])
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

children なのに root (親)がpushされているのが気になりました。子かどうかというより、次にtraveseあるいは処理されるべきノード、のような命名が良いのではないでしょうか。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

node_to_traverseに変更しました

102/sol2_loop.py Outdated
Comment on lines +13 to +15
level_order = []
if root is None:
return level_order
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

rootがNoneのとき、level_order という変数すら不要なフローにしたいです。

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

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

なるほど。不要な変数定義を極力避けたいのですね...。気をつけます。

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 は空のリストです。rootがNoneならlevel_orderを返します。
  • rootがNoneなら空のリストを返します。

どちらが説明として分かりやすいでしょうか。

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 = [] の宣言と root is None ロジックの間に、うっかり level_order を変更するようなコードが差し込まれてバグる、ということが有り得ます。このバグは簡単なテストで防げますが、それを踏まえても採用するメリットは(私は)小さいように思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ご説明ありがとうございます。日本語でコードを説明されると納得できました。
実際の現場での視点は、経験不足で持てていませんが、意識してみたいと思います。

102/memo.md Outdated
- if elseで例外処理を行うより、ifで例外だけを処理した方が良い
> 「機械の使い方の説明です。まず、青いランプが5つついていることを確認してください。ついている場合、…使い方の説明…。ランプがついていなかった場合は、直ちに使用を中止して事務所に連絡してください。…機械の使い方の続き…。」

- queueを使った BFS (sol4.py)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

このファイルがコミットされていないように見えます。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

sol3.pyですね。詳しく見ていただきありがとうございます。

102/sol3.py Outdated
Comment on lines +16 to +17
queue = deque()
queue.append(root)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これで初期化できそうです。

Suggested change
queue = deque()
queue.append(root)
queue = deque([root])

Comment on lines +20 to +21
level_size = len(queue)
for _ in range(level_size):
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_size はタプルにしてキューに詰めるか、next_level_nodes: list[TreeNode] に次の階層のnodeをappendしてqueueに差し替える、という実装の方が好みです。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

なるほど、そのような実装もあるのですね。こちらを好む理由も理解しました。
今回は現状の実装を採用しようと思います。

102/sol3.py Outdated
for _ in range(level_size):
node = queue.popleft()
values_by_level.append(node.val)
for child in [node.left, node.right]:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

コードごとにタプルだったりリストだったりしますが、(少なくとも自分の中での)ルールが決まっていると良いと思います。ちなみに、都度タプルやリストが生成されていることも留意しておくとよいでしょう。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

タプルに統一するようにします。こちらの方がオーバーヘッドが小さそうですので。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちらの方がオーバーヘッドが小さそう

時間があれば、それぞれのオーバーヘッド(の差)と、その要因を調べてみるとよいと思います。

# self.val = val
# self.left = left
# self.right = right
class Solution:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ロジックが把握しにくく感じました。自分に関数型言語の素養があまりないためかもしれません。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants