Conversation
| 「この関数は、root1 をただ読むだけだろう」と思い込んでいて、「マージの結果として新しいツリーを返すだけだろう」と予想している状態で、実際は root1 をガンガン上書きする関数が呼ばれたら、 | ||
| 後から root1 を再利用しようとしたときに予期せぬ値や構造になっていて「えっ、なんでツリーが書き換わってるの?」と驚くことになりそうだと思った。 | ||
| もし破壊的に書くなら、 | ||
| ライブラリのドキュメントに「破壊的です」と書くかな。 |
There was a problem hiding this comment.
全く新しい木を構築していく方法もあると思います。step3のコードでも下記のようなケースにroot1とmergeTreesの返り値でポインタの共有部分があるとroot1への変更が返り値にも影響してしまう場合があるのは気をつけないといけないと思いました。pythonのポインタについて誤解していたらごめんなさい
root1 = TreeNode(1)
root2 = None
merged_tree = mergeTrees(root1, root2)
print(merged_tree.val) # 1
root1.val += 1
print(merged_tree.val) # 2| 「この関数は、root1 をただ読むだけだろう」と思い込んでいて、「マージの結果として新しいツリーを返すだけだろう」と予想している状態で、実際は root1 をガンガン上書きする関数が呼ばれたら、 | ||
| 後から root1 を再利用しようとしたときに予期せぬ値や構造になっていて「えっ、なんでツリーが書き換わってるの?」と驚くことになりそうだと思った。 | ||
| もし破壊的に書くなら、 | ||
| ライブラリのドキュメントに「破壊的です」と書くかな。 |
There was a problem hiding this comment.
Ruby では ! をつけることによって表現する流儀がありますね。Python では変数名に使えないですが。
https://www.ruby-lang.org/en/documentation/faq/7/#destructive-metho
| merged_node.right = node2.right | ||
|
|
||
| return merged_root | ||
| ``` |
There was a problem hiding this comment.
Python は、メンバ変数へのポインターが持てないので、どうしても繰り返し感がでますね。下のような方法は一応考えてみました。
class Solution:
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
roots = list(filter(None, [root1, root2]))
if not roots:
return None
root = TreeNode()
stack = [(root, roots)]
while stack:
dst_node, src_nodes = stack.pop()
dst_node.val = sum(n.val for n in src_nodes)
lefts = [n.left for n in src_nodes if n.left]
if lefts:
dst_node.left = TreeNode()
stack.append((dst_node.left, lefts))
rights = [n.right for n in src_nodes if n.right]
if rights:
dst_node.right = TreeNode()
stack.append((dst_node.right, rights))
return rootThere was a problem hiding this comment.
これも別に良いコードではないですが、C++ だとどこに書き込むかをスタックに積むことができるので、少し簡単になるのです。それを擬似的に Python で表現してみました。
from functools import partial
class Solution:
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
dummy = TreeNode()
stack = [(partial(dummy.__setattr__, "left"), [root1, root2])]
while stack:
write_node, nodes = stack.pop()
nodes = list(filter(None, nodes))
if not nodes:
continue
val = sum(n.val for n in nodes)
output = TreeNode(val)
write_node(output)
for child in ['left', 'right']:
stack.append((partial(output.__setattr__, child), [n.__getattribute__(child) for n in nodes]))
return dummy.leftThere was a problem hiding this comment.
setattr、getattr、attrgetter あたりを使うべきでしょうね。
https://docs.python.org/3/library/functions.html#setattr
https://docs.python.org/3/library/operator.html#operator.attrgetter
| if root1 is None: | ||
| return root2 | ||
| if root2 is None: | ||
| return root1 |
There was a problem hiding this comment.
Step 3の方法は、入力を破壊はしていないものの、マージ後の木と入力の木でノードが共有される可能性があります。
|
良さそうです! |
https://leetcode.com/problems/merge-two-binary-trees/description/