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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 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

# preorder, inorderを受け取るとその部分木を生成する関数を組むように制作した

class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
if len(preorder) == 0:
return None

node = TreeNode()
root_id = preorder[0]
index = inorder.index(root_id)
node.val = root_id
Copy link

Choose a reason for hiding this comment

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

ここの4行の変数名と中身の整合性が取れていない気がしました。自分なら以下のようにします

root_value = preorder[0]
root = TreeNode(root_value)
root_inorder_index = inorder.index(root_value)

Copy link

Choose a reason for hiding this comment

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

気になった点は、

  • root_idはidではなくvalueを取得しているはず
  • indexだけだと読み進めて何のindexだったのか忘れてしまった
  • root_idという変数を元にnodeを生成しているが、rootで良いのでは
  • nodeを宣言してから使うまでに距離がある
    辺りです

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。直してみました

left_inorder = inorder[:index]
left_preorder = preorder[1:1 + len(left_inorder)]
right_inorder = inorder[index + 1:]
right_preorder = preorder[1 + len(left_inorder):]
node.left = self.buildTree(left_preorder, left_inorder)
node.right = self.buildTree(right_preorder, right_inorder)

return node
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# olsen-blue: https://github.com/olsen-blue/Arai60/pull/29/files
# preorderの呼び出され方を考えると副作用のある関数を許せば関数が呼び出されるたびにpreorderのindexを1つ進めるだけでよくなる, スライス操作の方は確かにphase1でも書いたが個人的にも速度とかの低下が怖い
# hroc135: https://github.com/hroc135/leetcode/pull/28/files
# kazukiii: https://github.com/kazukiii/leetcode/pull/30/files
# seal-azarashi: https://github.com/seal-azarashi/leetcode/pull/29#discussion_r1813998042
# nittoco: https://github.com/nittoco/leetcode/pull/37/files

# 副作用のあるhelper関数を許す
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
preorder_index = -1
Copy link

@olsen-blue olsen-blue Feb 17, 2025

Choose a reason for hiding this comment

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

preorder_indexの初期値ですが、私もこの問題にStep1で取り組んだ時には -1 にしていました。
しかし、インデックスが -1 というのは、パッと見で、末尾を指定しているようにも見えなくないなということが、その後気になり修正しました。「+= 1」の更新のタイミングを後ろにするだけでこの点解消できるので、ご検討ください。

hayashi-ay/leetcode#43

def build_tree_helper(left: int, right: int) -> Optional[TreeNode]:
if left > right:
return None
nonlocal preorder_index
preorder_index += 1
node = TreeNode(preorder[preorder_index])
inorder_split_index = inorder.index(preorder[preorder_index]) # ここの行をmapにすると速くはなる
node.left = build_tree_helper(left, inorder_split_index - 1)
node.right = build_tree_helper(inorder_split_index + 1, right)
return node

return build_tree_helper(0, len(preorder) - 1)

# 範囲情報を入れてpreorder順に見ていく場合の実装(参考: https://github.com/nittoco/leetcode/pull/37/files)
from dataclasses import dataclass

@dataclass
class InorderPosition:
node: TreeNode
left_limit: int
right_limit: int

class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
dummy = TreeNode()
stack = [InorderPosition(dummy, inf, inf)]
node_val_to_inorder_index = {val: i for i, val in enumerate(inorder)}
for node_id in preorder:
inorder_split_index = node_val_to_inorder_index[node_id]
node = TreeNode(node_id)
back = stack[-1]
if inorder_split_index < back.left_limit:
back.node.left = node
stack.append(InorderPosition(node, inorder_split_index, back.left_limit))
continue
back = self.search_parent_of_right_child(inorder_split_index, stack)
back.node.right = node
stack.append(InorderPosition(node, inorder_split_index, back.right_limit))
Copy link

Choose a reason for hiding this comment

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

好みの問題だと思いますが、このように対照関係がある場合には自分はcontinueでインデントを下げる方法よりもif,elseを使いたくなります

Choose a reason for hiding this comment

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

同じ感覚です。continueは早期returnに近いイメージがあります。

自然言語で表現されているのがこちらですかね。機械の使用中止のところです。
https://discord.com/channels/1084280443945353267/1192728121644945439/1194203372115464272

Copy link

Choose a reason for hiding this comment

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

私はcontinueのほうが好みです。
if-elseだと後で使う可能性があるので脳のメモリを解放できないのが理由です。

return dummy.left

def search_parent_of_right_child(self, inorder_split_index: int, stack: list[InorderPosition]) -> InorderPosition:
Copy link

Choose a reason for hiding this comment

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

関数名が search で始まっていると、引数に対して変更を加えない印象があります。引数に対して変更を加えていることを明示的に表す名前のほうがよいと思います。

while stack:
if inorder_split_index < stack[-1].right_limit:
return stack[-1]
stack.pop()
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 副作用はあるが, sliceとかコピーをなしにして自分がギリギリ思いつきそうな解答を書いた

class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
preorder_index = -1
Copy link

Choose a reason for hiding this comment

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

preorder_index が副作用なのは追いにくく、確かにこう書くこともありますが、個人的にはどれくらい消費したかを返り値で返して欲しいですね。

あとはコメント集にいくつか他の解法もあった気がしますが、おまけですね。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.1rv0z8fm6lc3

Copy link
Owner Author

Choose a reason for hiding this comment

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

副作用を直したバージョンをphase4.pyに追加しました

node_val_to_inorder_index = {val: i for i, val in enumerate(inorder)}
def build_tree_helper(left: int, right: int):
if left > right:
return
nonlocal preorder_index
preorder_index += 1
split_index = node_val_to_inorder_index[preorder[preorder_index]]
node = TreeNode(preorder[preorder_index])
node.left = build_tree_helper(left, split_index - 1)
node.right = build_tree_helper(split_index + 1, right)
return node
return build_tree_helper(0, len(inorder) - 1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# https://github.com/SuperHotDogCat/coding-interview/pull/43#discussion_r1958958113
# このコードを買いている時どうも命名に気を配れていなかった。数字でノード1つを指定できるのでidという名前にしていたがTreeNodeの名前はvalなのでそこが違うために困惑させたコードになってしまっていた
# あとは変数を定義してから使うまでを離さないように

class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
if len(preorder) == 0:
return None

root_val = preorder[0]
root = TreeNode(root_val)
root_inorder_index = inorder.index(root_val)
root.left = self.buildTree(preorder[1:1 + root_inorder_index], inorder[:root_inorder_index])
root.right = self.buildTree(preorder[1 + root_inorder_index:], inorder[root_inorder_index + 1:])
return root

Copy link

Choose a reason for hiding this comment

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

preorderをスライスするのは分かりにくい気もしますが、発想は面白く感じました。

# https://github.com/SuperHotDogCat/coding-interview/pull/43/files#r1958006329
# https://github.com/SuperHotDogCat/coding-interview/pull/43/files#r1957333097 コメント: 個人的にはどれくらい消費したかを返り値で返して欲しいですね<-消費したかを返す実装で自分は沼にハマってしまったのでpreorder_indexを返すように関数を変更して副作用を消すようにした
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
node_val_to_inorder_index = {val: i for i, val in enumerate(inorder)}

def build_tree_helper(left: int, right: int, preorder_index: int):
# preorder_indexは常に次探索すべきpreorderのindexを指すように制作
if left > right:
return None, preorder_index
node = TreeNode(preorder[preorder_index])
split_index = node_val_to_inorder_index[preorder[preorder_index]]
preorder_index += 1
node.left, preorder_index = build_tree_helper(left, split_index - 1, preorder_index)
node.right, preorder_index = build_tree_helper(split_index + 1, right, preorder_index)
return node, preorder_index
return build_tree_helper(0, len(inorder) - 1, 0)[0]