Conversation
| - 空間計算量 O(n)+O(h) | ||
|
|
||
| - https://github.com/mamo3gr/arai60/blob/102_binary-tree-level-order-traversal/102_binary-tree-level-order-traversal/step2.py | ||
| - 行きがけ順の再帰 |
There was a problem hiding this comment.
これ、素直に対応するループに直せますか。再帰呼ぶかわりにスタックにやることを積んで 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
There was a problem hiding this comment.
新しく書きました。pythonのsys.setrecursionlimitなど知らなかったので勉強になりました。
https://docs.python.org/3/library/sys.html#sys.setrecursionlimit
a04d99e to
a37e99f
Compare
102/sol1.py
Outdated
| 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))] | ||
| ) |
There was a problem hiding this comment.
何をやりたいのか分かりづらいので、サブルーチンにして説明的な名前を付けると良いと思いました。List[List[int]] の長さを揃えたいんですよね。
102/sol1.py
Outdated
| for i in range(len(left_level_order)): | ||
| merged_level_order.append(left_level_order[i] + right_level_order[i]) |
There was a problem hiding this comment.
長さの違うlist同士を処理するなら、itertools.zip_longest が使えそうです。
https://docs.python.org/3/library/itertools.html#itertools.zip_longest
| 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) |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
add ではなくて append がより正確に思いました。また、append先になる level_order も引数に取ったほうが、関数呼び出しのパラメータを見て何をするのか分かりやすそうに思いました。
102/sol2_loop.py
Outdated
| level_order = [] | ||
| if root is None: | ||
| return level_order | ||
| children_pushed = deque([(0, root)]) |
There was a problem hiding this comment.
children なのに root (親)がpushされているのが気になりました。子かどうかというより、次にtraveseあるいは処理されるべきノード、のような命名が良いのではないでしょうか。
102/sol2_loop.py
Outdated
| level_order = [] | ||
| if root is None: | ||
| return level_order |
There was a problem hiding this comment.
rootがNoneのとき、level_order という変数すら不要なフローにしたいです。
| level_order = [] | |
| if root is None: | |
| return level_order | |
| if root is None: | |
| return [] | |
| level_order = [] |
There was a problem hiding this comment.
なるほど。不要な変数定義を極力避けたいのですね...。気をつけます。
There was a problem hiding this comment.
level_orderは空のリストです。rootがNoneならlevel_orderを返します。- rootが
Noneなら空のリストを返します。
どちらが説明として分かりやすいでしょうか。
There was a problem hiding this comment.
あと、実際の開発では、仕様の追加やリファクタリングの際に、level_order = [] の宣言と root is None ロジックの間に、うっかり level_order を変更するようなコードが差し込まれてバグる、ということが有り得ます。このバグは簡単なテストで防げますが、それを踏まえても採用するメリットは(私は)小さいように思います。
There was a problem hiding this comment.
ご説明ありがとうございます。日本語でコードを説明されると納得できました。
実際の現場での視点は、経験不足で持てていませんが、意識してみたいと思います。
102/memo.md
Outdated
| - if elseで例外処理を行うより、ifで例外だけを処理した方が良い | ||
| > 「機械の使い方の説明です。まず、青いランプが5つついていることを確認してください。ついている場合、…使い方の説明…。ランプがついていなかった場合は、直ちに使用を中止して事務所に連絡してください。…機械の使い方の続き…。」 | ||
|
|
||
| - queueを使った BFS (sol4.py) |
There was a problem hiding this comment.
sol3.pyですね。詳しく見ていただきありがとうございます。
102/sol3.py
Outdated
| queue = deque() | ||
| queue.append(root) |
There was a problem hiding this comment.
これで初期化できそうです。
| queue = deque() | |
| queue.append(root) | |
| queue = deque([root]) |
| level_size = len(queue) | ||
| for _ in range(level_size): |
There was a problem hiding this comment.
キューにはなるべく処理に必要な情報がセットで入っていてほしいと思います(あくまで私の場合)。したがって、キュー外での管理になっている level_size はタプルにしてキューに詰めるか、next_level_nodes: list[TreeNode] に次の階層のnodeをappendしてqueueに差し替える、という実装の方が好みです。
There was a problem hiding this comment.
なるほど、そのような実装もあるのですね。こちらを好む理由も理解しました。
今回は現状の実装を採用しようと思います。
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]: |
There was a problem hiding this comment.
コードごとにタプルだったりリストだったりしますが、(少なくとも自分の中での)ルールが決まっていると良いと思います。ちなみに、都度タプルやリストが生成されていることも留意しておくとよいでしょう。
There was a problem hiding this comment.
タプルに統一するようにします。こちらの方がオーバーヘッドが小さそうですので。
There was a problem hiding this comment.
こちらの方がオーバーヘッドが小さそう
時間があれば、それぞれのオーバーヘッド(の差)と、その要因を調べてみるとよいと思います。
| # self.val = val | ||
| # self.left = left | ||
| # self.right = right | ||
| class Solution: |
There was a problem hiding this comment.
ロジックが把握しにくく感じました。自分に関数型言語の素養があまりないためかもしれません。
https://leetcode.com/problems/binary-tree-level-order-traversal/description/