Skip to content

Solved: 617. Merge Two Binary Trees#23

Open
Fuminiton wants to merge 1 commit intomainfrom
solve-problem23
Open

Solved: 617. Merge Two Binary Trees#23
Fuminiton wants to merge 1 commit intomainfrom
solve-problem23

Conversation

@Fuminiton
Copy link
Copy Markdown
Owner

def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
if not root1 and not root2:
return None
if not root1:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Noneとの比較には is Noneを使うべきだと思います。
https://pep8-ja.readthedocs.io/ja/latest/#id41

また、 本当は if x is not None と書いているつもりで、 if x と書いている場合は注意してください - たとえば、デフォルトの値がNoneになる変数や引数に、何かしら別の値が設定されているかどうかをテストする場合です。この「別の値」は、ブール型のコンテクストでは False と評価される(コンテナのような)型かもしれませんよ!

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.

レビュー、リンクの共有までありがとうございます。

https://github.com/seal-azarashi/leetcode/pull/22/files#r1778932434
> それで、どんなユースケースでこの mergeTrees は使われるんでしょうか。

root1を基準に更新していく解法が LeetCode 上の Solutions によく載っていたが、破壊的な実装なので微妙ではと思った。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

一部のノードを共有すると、他の破壊的なメソッドとの相性で残念なことになるかもしれませんね。

Comment on lines +40 to +43
if not root1:
return root2
if not root2:
return root1
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.

deepcopyで返す or 下に流さないと、mergeTreesの返り値を操作したときに入力を書き換えてしまう可能性があるんですね。。見逃していました。

shining-ai/leetcode#23 (comment)

root2をルートとするツリーについては、引数で渡ってきたものをそのまま使用しているので、この書き方だとmergeTreesの返り値のTreeにroot2の一部が使われてしまいます。この関数自体では非破壊的かもしれないですが、mergeTreesの返り値のTreeの操作を行うとroot2のツリーを書き換えてしまう可能性があります。

Comment on lines +52 to +55
elif node1:
merged_node.val = node1.val
elif node2:
merged_node.val = node2.val
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

この場合、終端を表す番兵を使う手はありますよ。
TreeNode(0)
を node1, node2 にとりあえず入れておきます。

Copy link
Copy Markdown
Owner Author

@Fuminiton Fuminiton Mar 17, 2025

Choose a reason for hiding this comment

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

ご指摘ありがとうございます。
あまり番兵を使ったことがなかったので避けていましたが、ここかなり簡潔になりますね。

            node1 = node1 if node1 else TreeNode(0)
            node2 = node2 if node2 else TreeNode(0)
            merged_node.val = node1.val + node2.val

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

@Fuminiton Fuminiton Mar 18, 2025

Choose a reason for hiding this comment

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

以下の三項演算子の部分も単にnode1.rightで済むようになるのですね。

                    node1.right if node1 else None,
                    node2.right if node2 else 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.

if (node1 and node1.left) or (node2 and node2.left):

これもです。node1 node2 がある前提で書けます。

Copy link
Copy Markdown
Owner Author

@Fuminiton Fuminiton Mar 19, 2025

Choose a reason for hiding this comment

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

おっしゃる通りですね。
番兵使った方が明らかに簡潔になりました。

ご指摘ありがとうございます。

SENTINEL = TreeNode(0)

class Solution:
    def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
        if root1 is None and root2 is None:
            return None

        merged = TreeNode()
        stack = [(root1, root2, merged)]
        while stack:
            node1, node2, merged_node = stack.pop()
            if node1 is None:
                node1 = SENTINEL
            if node2 is None:
                node2 = SENTINEL
            merged_node.val = node1.val + node2.val            
            if node1.left is not None or node2.left is not None:
                merged_node.left = TreeNode()
                stack.append((node1.left, node2.left, merged_node.left))
            if node1.right is not None or node2.right is not None:
                merged_node.right = TreeNode()
                stack.append((node1.right, node2.right, merged_node.right))
        return merged

if not root1 and not root2:
return None
if not root1 or not root2:
return root1 if root1 else root2
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

三項演算子が読み手の認知負荷を上げてしまう可能はなくはないです。
olsen-blue/Arai60#5 (comment)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pythonの三項演算子読みにくいですね

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これ、私が感じるのは、なんで、わざわざ混ぜた後に分離するのか、です。

右手も左手も何も持っていない場合は、None を返してください。
右手に何も持っていない、または、左手に何も持っていない場合は、「右手に物を持っている場合は右手で持っているものを、そうでない場合は左手に持っているものを」返してください。

Python の三項演算子、目が左右に振られるんですよね。

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.

右手も左手も何も持っていない場合は、None を返してください。右手に何も持っていない、または、左手に何も持っていない場合は、「右手に物を持っている場合は右手で持っているものを、そうでない場合は左手に持っているものを」返してください。

確かに身近な言葉に直してみると、不自然な操作ですね
変な説明になっていないか考えながら実装しようと思います。

今回ですと、「右手に何も持っていない、または、左手に何も持っていない場合は、持っている方を返してください」(return root1 or root2)が自然かと思いました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

私は、
右手が空なら左手で持っているものを返してください。
左手が空なら右手で持っているものを返してください。
でいいと思います。

@hroc135
Copy link
Copy Markdown

hroc135 commented Mar 31, 2025

気になったところは全てコメント済みでした。いいと思います

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.

5 participants