-
Notifications
You must be signed in to change notification settings - Fork 0
105.construct binary tree from preorder and inorder traversal #28
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: main
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,30 @@ | ||
|
|
||
| # 105. Construct Binary Tree from Preorder and Inorder Traversal | ||
|
|
||
| - sol1: 愚直な方針。再帰でpreorderの先頭が根であり、preorderでその位置を特定して再帰。 | ||
| - 時間計算量: 根の探索とスライス作成で最悪O(n**2) | ||
| - 空間計算量: スライス作成で最悪O(n**2) | ||
| - 再帰スタック:O(h), 最悪O(n) | ||
| - 時間の具体的な見積もり:n = 3000, Python 10^7として 3000 **2 / 10^7 = 0.9s | ||
| - sol2: 再帰は変えずに、inorder の値→index の辞書を作って (O(1)) で位置を引き、再帰は「配列の範囲(左右境界)」で表す(スライスしない)。 | ||
| - 時間計算量: 最初の val_to_indexの計算でO(n) | ||
| - 空間計算量: val_to_indexのみなのでO(n) | ||
| - 再帰スタックは上と同じ | ||
| - 結構速くなった | ||
| - 時間の具体的な見積もり:n = 3000, Python 10^7として 3000 / 10^7 = 3 * 10**-4 | ||
|
|
||
| https://github.com/mamo3gr/arai60/blob/105_construct-binary-tree-from-preorder-and-inorder-traversal/105_construct-binary-tree-from-preorder-and-inorder-traversal/step2.py | ||
|
|
||
| - 区間を表すclass Spanを作っている | ||
| - 無駄がないといういみでは自分の左端とnum_childrenを持つ形でも良さそう | ||
| - frontierを使った再帰ループでも書いている | ||
|
|
||
| コメント集 | ||
| https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.1rv0z8fm6lc3 | ||
|
|
||
| - inorderの順番で構築: https://discord.com/channels/1084280443945353267/1247673286503039020/1300957719074967603 | ||
| - C++をPythonに変換した (sol3) | ||
| - inorderで自分より前(自分の左)、preorder自分より後(=自分の子供)のノードをleftでまとめて回収 | ||
| - 自分の左は確定しているが、右が確定していないノードをstackに積む。これらはinorderで探索しているので、親が先にstackに入る(後に出る)。よって、これらを右に重ねていけばよい。 | ||
| - 自分で書くのは無理 | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| from typing import List, Optional | ||
|
|
||
|
|
||
| # 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 | ||
|
|
||
|
|
||
| class Solution: | ||
| def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: | ||
| assert len(preorder) == len(inorder), f"{len(inorder)}, {len(preorder)}" | ||
| if len(preorder) == 0: | ||
| return None | ||
| root = TreeNode(preorder[0]) | ||
| if len(preorder) == 1: | ||
| return root | ||
| idx_inorder_root = -1 | ||
| for idx_inorder in range(len(inorder)): | ||
| if inorder[idx_inorder] == root.val: | ||
| idx_inorder_root = idx_inorder | ||
| break | ||
| left_children_inorder = inorder[:idx_inorder_root] | ||
| left_children_preorder = preorder[1 : idx_inorder_root + 1] | ||
| right_children_inorder = inorder[idx_inorder_root + 1 :] | ||
| right_children_preorder = preorder[idx_inorder_root + 1 :] | ||
| root.left = self.buildTree(left_children_preorder, left_children_inorder) | ||
| root.right = self.buildTree(right_children_preorder, right_children_inorder) | ||
| return root |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| from typing import List, Optional | ||
|
|
||
|
|
||
| # Definition for a binary tree node. | ||
| try: | ||
| TreeNode # type: ignore[name-defined] | ||
| except NameError: | ||
|
|
||
| class TreeNode: | ||
| def __init__(self, val=0, left=None, right=None): | ||
| self.val = val | ||
| self.left = left | ||
| self.right = right | ||
|
|
||
|
|
||
| class Solution: | ||
| def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: | ||
| assert len(preorder) == len(inorder), f"{len(inorder)}, {len(preorder)}" | ||
| if not preorder: | ||
| return None | ||
| inorder_val_to_idx = {} | ||
| for i, val in enumerate(inorder): | ||
| inorder_val_to_idx[val] = i | ||
|
|
||
| def buildTree_w_index( | ||
| pre_left: int, in_left: int, num_children: int | ||
|
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. 私はこの書き方を検討しきれていませんでした。確かに、子の数がわかっているのでこの値に名前をつけて引数にするのが、とてもわかりやすく感じました。 |
||
| ) -> Optional[TreeNode]: | ||
| if num_children <= 0: | ||
| return None | ||
| root = TreeNode(preorder[pre_left]) | ||
| if num_children == 1: | ||
| return root | ||
| idx_root_inorder = inorder_val_to_idx[root.val] | ||
| num_left_children = idx_root_inorder - in_left | ||
|
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. 好みの範疇ですが、 |
||
| num_right_children = num_children - num_left_children - 1 | ||
| root.left = buildTree_w_index(pre_left + 1, in_left, num_left_children) | ||
| root.right = buildTree_w_index( | ||
| pre_left + 1 + num_left_children, | ||
| idx_root_inorder + 1, | ||
| num_right_children, | ||
| ) | ||
| return root | ||
|
|
||
| return buildTree_w_index(0, 0, len(preorder)) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| from typing import Dict, List, Optional | ||
|
|
||
|
|
||
| # class TreeNode: | ||
| # def __init__( | ||
| # self, | ||
| # val: int = 0, | ||
| # left: Optional["TreeNode"] = None, | ||
| # right: Optional["TreeNode"] = None, | ||
| # ): | ||
| # self.val = val | ||
| # self.left = left | ||
| # self.right = right | ||
|
|
||
|
|
||
| class Solution: | ||
| def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: | ||
| if not preorder: | ||
| return None | ||
|
|
||
| preorder_position = {val: i for i, val in enumerate(preorder)} | ||
|
|
||
| # contains all nodes whose .right hasn't been decided yet. | ||
| stack = [] | ||
|
|
||
| def gather_descendants(node_position): | ||
| child = None | ||
| while stack: | ||
| back = stack[-1] | ||
| if preorder_position[back.val] < node_position: | ||
| break | ||
| stack.pop() | ||
| back.right = child | ||
| child = back | ||
| return child | ||
|
|
||
| for val in inorder: | ||
| node = TreeNode(val) | ||
| node_position = preorder_position[node.val] | ||
| node.left = gather_descendants(node_position) | ||
| stack.append(node) | ||
|
|
||
| return gather_descendants(-(10**30)) | ||
|
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. この数字がどうやって決まっているのかわかりづらいので、Python にするのだったら
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. ご指摘の通りですね、ありがとうございます |
||
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.
メソッド名の
wが何かを読み取れなかったので、略ではなく単語を使うことをお勧めします。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.
withの略でしたが、わかりづらいのかもしれませんね。省略せずに書こうと思います。