-
Notifications
You must be signed in to change notification settings - Fork 0
solved construct_binary_tree_from_preorder_and_inorder_traversal #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: arai60
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. preorder_indexの初期値ですが、私もこの問題にStep1で取り組んだ時には -1 にしていました。 |
||
| 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)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 好みの問題だと思いますが、このように対照関係がある場合には自分はcontinueでインデントを下げる方法よりもif,elseを使いたくなります There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 同じ感覚です。continueは早期returnに近いイメージがあります。 自然言語で表現されているのがこちらですかね。機械の使用中止のところです。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 私はcontinueのほうが好みです。 |
||
| return dummy.left | ||
|
|
||
| def search_parent_of_right_child(self, inorder_split_index: int, stack: list[InorderPosition]) -> InorderPosition: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. preorder_index が副作用なのは追いにくく、確かにこう書くこともありますが、個人的にはどれくらい消費したかを返り値で返して欲しいですね。 あとはコメント集にいくつか他の解法もあった気がしますが、おまけですね。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここの4行の変数名と中身の整合性が取れていない気がしました。自分なら以下のようにします
There was a problem hiding this comment.
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を宣言してから使うまでに距離がある辺りです
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。直してみました