-
Notifications
You must be signed in to change notification settings - Fork 0
776. Split BST #49
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
Open
TORUS0818
wants to merge
1
commit into
main
Choose a base branch
from
776
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
776. Split BST #49
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,377 @@ | ||
| # Step1 | ||
|
|
||
| かかった時間:解けず | ||
|
|
||
| 計算量: | ||
|
|
||
| Nをノード数として | ||
| - 時間計算量:O(N) | ||
| - 空間計算量:O(N) | ||
|
|
||
| ```python | ||
| from lintcode import ( | ||
| TreeNode, | ||
| ) | ||
|
|
||
| """ | ||
| Definition of TreeNode: | ||
| class TreeNode: | ||
| def __init__(self, val): | ||
| self.val = val | ||
| self.left, self.right = None, None | ||
| """ | ||
|
|
||
| class Solution: | ||
| """ | ||
| @param root: the given tree | ||
| @param v: the target value | ||
| @return: the root TreeNode after splitting | ||
| """ | ||
| def split_b_s_t(self, root: TreeNode, v: int) -> TreeNode: | ||
| # write your code here | ||
| def count_nodes(root: TreeNode) -> int: | ||
| if not root: | ||
| return 0 | ||
|
|
||
| queue = [root] | ||
| count = 0 | ||
| while queue: | ||
| next_queue = [] | ||
| for node in queue: | ||
| count += 1 | ||
| if node.left: | ||
| next_queue.append(node.left) | ||
| if node.right: | ||
| next_queue.append(node.right) | ||
| queue = next_queue | ||
|
|
||
| return count | ||
|
|
||
|
|
||
| def split_b_s_t_helper( | ||
| root: TreeNode, | ||
| v: int | ||
| ) -> tuple[TreeNode, TreeNode]: | ||
| if not root: | ||
| return None, None | ||
|
|
||
| if root.val <= v: | ||
| small_root, large_root = split_b_s_t_helper(root.right, v) | ||
| root.right = small_root | ||
| return root, large_root | ||
| else: | ||
| small_root, large_root = split_b_s_t_helper(root.left, v) | ||
| root.left = large_root | ||
| return small_root, root | ||
|
|
||
|
|
||
| small_root, large_root = split_b_s_t_helper(root, v) | ||
|
|
||
| small_tree_nodes_count = count_nodes(small_root) | ||
| large_tree_nodes_count = count_nodes(large_root) | ||
| if small_tree_nodes_count < large_tree_nodes_count: | ||
| return large_root | ||
| if small_tree_nodes_count > large_tree_nodes_count: | ||
| return small_root | ||
|
|
||
| if small_root.val < large_root.val: | ||
| return large_root | ||
| else: | ||
| return small_root | ||
| ``` | ||
| 思考ログ: | ||
| - leetcodeで有料の問題だったので、lintcodeの該当する問題を解きました | ||
| - 本家:https://leetcode.com/problems/split-bst/description/ | ||
| - 若干内容が異なっている模様 | ||
| - 一つずつ問題を解決していけばいいものを一気に解決しようとしてよく分からなくなる、という悪い癖が出た | ||
| - 条件を満たすように木を分ける、ノードの数を数える、ノードの数を比較する、根の値を比較する | ||
| - 木の分割について | ||
| - ```split_b_s_t_helper```は、ノードを与えると、条件を満たすように2つの木(```small_tree```, ```large_tree```)に分けてそれらのrootを返す関数 | ||
| - 現在のノードの値を確認してv以下なら、そのノードと左の子以降は```small_tree```の部分木になる | ||
| - ノードの右の子以降は```split_b_s_t_helper```を使って```sub_small_tree```と```sub_large_tree```に分解する | ||
| - ```small_tree```の右の子に上記の```sub_small_tree```を繋ぐ | ||
| - ```large_tree```は上記の```sub_large_tree```を採用する | ||
| - vより大きい場合も同様の考え方 | ||
|
|
||
| # Step2 | ||
|
|
||
| 講師役目線でのセルフツッコミポイント: | ||
|
|
||
| 参考にした過去ログなど: | ||
| - https://github.com/ryosuketc/leetcode_arai60/pull/36 | ||
| - https://github.com/olsen-blue/Arai60/pull/48 | ||
| - 根から作っていくタイプの解法 | ||
| - https://github.com/Ryotaro25/leetcode_first60/pull/50 | ||
| - https://github.com/Ryotaro25/leetcode_first60/pull/50/files#r1912058276 | ||
| - https://github.com/goto-untrapped/Arai60/pull/54 | ||
| - https://github.com/Yoshiki-Iwasa/Arai60/pull/41 | ||
| - 型について | ||
| - https://github.com/Yoshiki-Iwasa/Arai60/pull/41/files#r1712673452 | ||
| - https://github.com/Mike0121/LeetCode/pull/16 | ||
| - https://github.com/shining-ai/leetcode/pull/47 | ||
| - stackに```("go" or "back", root, None)```の形で積んでいく方法 | ||
| - https://github.com/hayashi-ay/leetcode/pull/53 | ||
|
|
||
| ```python | ||
| from lintcode import ( | ||
| TreeNode, | ||
| ) | ||
|
|
||
| """ | ||
| Definition of TreeNode: | ||
| class TreeNode: | ||
| def __init__(self, val): | ||
| self.val = val | ||
| self.left, self.right = None, None | ||
| """ | ||
|
|
||
| class Solution: | ||
| """ | ||
| @param root: the given tree | ||
| @param v: the target value | ||
| @return: the root TreeNode after splitting | ||
| """ | ||
| def split_b_s_t(self, root: TreeNode, v: int) -> TreeNode: | ||
| # write your code here | ||
| def count_nodes(root: TreeNode) -> int: | ||
| if not root: | ||
| return 0 | ||
|
|
||
| queue = [root] | ||
| count = 0 | ||
| while queue: | ||
| next_queue = [] | ||
| for node in queue: | ||
| count += 1 | ||
| if node.left: | ||
| next_queue.append(node.left) | ||
| if node.right: | ||
| next_queue.append(node.right) | ||
| queue = next_queue | ||
|
|
||
| return count | ||
|
|
||
|
|
||
| def split_b_s_t_helper( | ||
| root: TreeNode, | ||
| v: int | ||
| ) -> tuple[TreeNode]: | ||
| if not root: | ||
| return None, None | ||
|
|
||
| if root.val == v: | ||
| small_root = 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. small_root = root
small_root.right = None
large_root = root.rightの順で書いたほうが、同じ操作対象が連続で登場するので、短期記憶が汚染されにくくなり、認知負荷が少なくなると思います。
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. STEP3では、まさにこの点が気になって順序を修正しました(L335-L352) |
||
| large_root = root.right | ||
| small_root.right = None | ||
| return small_root, large_root | ||
|
|
||
| if root.val < v: | ||
| small_root, large_root = split_b_s_t_helper(root.right, v) | ||
| root.right = small_root | ||
| return root, large_root | ||
| else: | ||
| small_root, large_root = split_b_s_t_helper(root.left, v) | ||
| root.left = large_root | ||
| return small_root, root | ||
|
|
||
|
|
||
| small_root, large_root = split_b_s_t_helper(root, v) | ||
|
|
||
| small_tree_nodes_count = count_nodes(small_root) | ||
| large_tree_nodes_count = count_nodes(large_root) | ||
| if small_tree_nodes_count < large_tree_nodes_count: | ||
| return large_root | ||
| if small_tree_nodes_count > large_tree_nodes_count: | ||
| return small_root | ||
|
|
||
| if small_root.val < large_root.val: | ||
| return large_root | ||
| else: | ||
| return small_root | ||
| ``` | ||
| 思考ログ: | ||
| - `split_b_s_t_helper`にて、`v`が見つかった時点で打ち切って良い | ||
|
|
||
| loop版 | ||
| ```python | ||
| from lintcode import ( | ||
| TreeNode, | ||
| ) | ||
|
|
||
| """ | ||
| Definition of TreeNode: | ||
| class TreeNode: | ||
| def __init__(self, val): | ||
| self.val = val | ||
| self.left, self.right = None, None | ||
| """ | ||
|
|
||
| class Solution: | ||
| """ | ||
| @param root: the given tree | ||
| @param v: the target value | ||
| @return: the root TreeNode after splitting | ||
| """ | ||
| def split_b_s_t(self, root: TreeNode, v: int) -> TreeNode: | ||
| # write your code here | ||
| def count_nodes(root: TreeNode) -> int: | ||
| if not root: | ||
| return 0 | ||
|
|
||
| queue = [root] | ||
| count = 0 | ||
| while queue: | ||
| next_queue = [] | ||
| for node in queue: | ||
| count += 1 | ||
| if node.left: | ||
| next_queue.append(node.left) | ||
| if node.right: | ||
| next_queue.append(node.right) | ||
| queue = next_queue | ||
|
|
||
| return count | ||
|
|
||
|
|
||
| def split_b_s_t_into_two_subtrees( | ||
| root: TreeNode, | ||
| v: int | ||
| ) -> tuple[TreeNode]: | ||
| node = root | ||
| stack = [] | ||
| while node: | ||
| stack.append(node) | ||
| if node.val > v: | ||
| node = node.left | ||
| else: | ||
| node = node.right | ||
|
|
||
| small_subtree_root = None | ||
| large_subtree_root = None | ||
| while stack: | ||
| node = stack.pop() | ||
| if node.val > v: | ||
| node.left = large_subtree_root | ||
| large_subtree_root = node | ||
| else: | ||
| node.right = small_subtree_root | ||
| small_subtree_root = node | ||
|
|
||
| return small_subtree_root, large_subtree_root | ||
|
|
||
|
|
||
| small_root, large_root = split_b_s_t_into_two_subtrees(root, v) | ||
|
|
||
| small_tree_nodes_count = count_nodes(small_root) | ||
| large_tree_nodes_count = count_nodes(large_root) | ||
| if small_tree_nodes_count < large_tree_nodes_count: | ||
| return large_root | ||
| if small_tree_nodes_count > large_tree_nodes_count: | ||
| return small_root | ||
|
|
||
| if small_root.val < large_root.val: | ||
| return large_root | ||
| else: | ||
| return small_root | ||
| ``` | ||
| - 同じことをやっているのにまだ再帰の方が考えやすい、という感覚がある | ||
| - 引継ぎの考え方がまだ甘いのとloopをトップダウンで考える癖があるのが原因な気がする | ||
|
|
||
| # Step3 | ||
|
|
||
| かかった時間:11min | ||
|
|
||
| ```python | ||
| from lintcode import ( | ||
| TreeNode, | ||
| ) | ||
|
|
||
| """ | ||
| Definition of TreeNode: | ||
| class TreeNode: | ||
| def __init__(self, val): | ||
| self.val = val | ||
| self.left, self.right = None, None | ||
| """ | ||
|
|
||
| class Solution: | ||
| """ | ||
| @param root: the given tree | ||
| @param v: the target value | ||
| @return: the root TreeNode after splitting | ||
| """ | ||
| def split_b_s_t(self, root: TreeNode, v: int) -> TreeNode: | ||
| # write your code here | ||
| def count_nodes(root: TreeNode) -> int: | ||
| if not root: | ||
| return 0 | ||
|
|
||
| stack = [root] | ||
| count = 0 | ||
| while stack: | ||
| node = stack.pop() | ||
| count += 1 | ||
| if node.right: | ||
| stack.append(node.right) | ||
| if node.left: | ||
| stack.append(node.left) | ||
|
|
||
| return count | ||
|
|
||
|
|
||
| def split_b_s_t( | ||
| root: TreeNode, | ||
| v: int | ||
| ) -> tuple[TreeNode]: | ||
| if not root: | ||
| return None, None | ||
|
|
||
| if root.val == v: | ||
| large_root = root.right | ||
| small_root = root | ||
| small_root.right = None | ||
| return small_root, large_root | ||
|
|
||
| if root.val < v: | ||
| sub_small_root, sub_large_root = split_b_s_t( | ||
| root.right, | ||
| v | ||
| ) | ||
| large_root = sub_large_root | ||
| small_root = root | ||
| small_root.right = sub_small_root | ||
| return small_root, large_root | ||
| else: | ||
| sub_small_root, sub_large_root = split_b_s_t( | ||
| root.left, | ||
| v | ||
| ) | ||
| large_root = root | ||
| large_root.left = sub_large_root | ||
| small_root = sub_small_root | ||
| return small_root, large_root | ||
|
|
||
|
|
||
| small_root, large_root = split_b_s_t(root, v) | ||
| small_tree_size = count_nodes(small_root) | ||
| large_tree_size = count_nodes(large_root) | ||
| if small_tree_size == large_tree_size: | ||
| if small_root.val < large_root.val: | ||
| return large_root | ||
| else: | ||
| return small_root | ||
|
|
||
| if small_tree_size < large_tree_size: | ||
| return large_root | ||
| else: | ||
| return small_root | ||
| ``` | ||
| 思考ログ: | ||
| - 再帰が自然に感じるので再帰で | ||
| - 木の深さ的にも問題なさそう(<<1000) | ||
|
|
||
| # Step4 | ||
|
|
||
| ```python | ||
| ``` | ||
| 思考ログ: | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
必ず large_root.val のほうが大きくなると思います。
とシンプルに書けると思います。ややパズルに感じられるため、コメントで補足したほうがよいと思います。
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.
本当ですね、起きていることへの解像度が低かったです。ありがとうございます。