-
Notifications
You must be signed in to change notification settings - Fork 0
Create 98. Validate Binary Search Tree.md #8
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
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,240 @@ | ||
| 1回目、20分ほどかけて下記のコードで時間切れとした。 | ||
| 下に降りていけばいいのはわかるが、どのようにすれば適切に値を比較できるか、結果を適切に返せるかが、かなり(頭の中で)ややこしくなってしまった。 | ||
|
|
||
| ## Inorderによる解法 | ||
| ### 1回目 | ||
| ```python | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
| def append_left_nodes(node, nodes): | ||
| while node: | ||
| nodes.append(node) | ||
| node = node.left | ||
|
|
||
| next_nodes = [] | ||
| append_left_nodes(root, next_nodes) #next_nodesに、rootからの左側への全てのノードを格納 | ||
| lower_bound = -float('inf') | ||
|
|
||
| while next_nodes: | ||
| checking_node = next_nodes.pop() # 未チェックの端(bottom)のノードを取り出す | ||
| if checking_node.val <= lower_bound: | ||
| return False | ||
| # 下限として、下のノード以上である必要があるため更新 | ||
| # left-bottomのノードは木の中で最小であることを利用 | ||
| lower_bound = checking_node.val | ||
| # 現在のノードに右側のノードがある場合↔︎右側のノードが現在のノードより大きい必要がある。をチェック | ||
| if checking_node.right: | ||
| if checking_node.right.val <= checking_node.val: | ||
| return False | ||
| # 右側ノードから見た時の、左側の脛手の値をチェックするため、 | ||
| # 右側のノードを親ノード見立ててチェックするため、加える。 | ||
| append_left_nodes(checking_node.right, next_nodes) | ||
| return True | ||
| ``` | ||
|
|
||
| ### 2~3回目 | ||
| ```python | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
| def append_left_nodes(node, nodes): | ||
| while node: | ||
| nodes.append(node) | ||
| node = node.left | ||
|
|
||
| lower_bound = -float('inf') | ||
| next_nodes = [] | ||
| append_left_nodes(root, next_nodes) | ||
|
|
||
| while next_nodes: | ||
| checking_node = next_nodes.pop() | ||
| if checking_node.val <= lower_bound: | ||
| return False | ||
| lower_bound = checking_node.val | ||
|
|
||
| if checking_node.right: | ||
| if checking_node.right.val <= checking_node.val: | ||
| return False | ||
| append_left_nodes(checking_node.right, next_nodes) | ||
| return True | ||
| ``` | ||
|
|
||
| ### 0回目 | ||
| --- | ||
| root =[5,4,6,null,null,3,7]が通らず。 | ||
| "3"が"5"より大きいので二分探索木の条件を満たさないめ。 | ||
| 都度上限と下限を更新して伝播させていく必要がある。 | ||
| ``` | ||
| 5 | ||
| / \ | ||
| 4 6 | ||
| / \ | ||
| 3 7 | ||
| ``` | ||
|
|
||
| ```python | ||
| i. | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
| left_flag = True | ||
| right_flag = True | ||
| if not root: | ||
| return True | ||
|
|
||
| if root.left: | ||
| if root.left.val >= root.val: | ||
| return False | ||
| left_flag = self.isValidBST(root.left) | ||
|
|
||
| if root.right: | ||
| if root.right.val <= root.val: | ||
| return False | ||
| right_flag = self.isValidBST(root.right) | ||
|
|
||
| return left_flag and right_flag | ||
|
|
||
| ii. | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
| if not root: | ||
| return True | ||
|
|
||
| if root.left: | ||
| if root.left.val >= root.val: | ||
| return False | ||
| if not self.isValidBST(root.left): | ||
| return False | ||
|
|
||
| if root.right: | ||
| if root.right.val <= root.val: | ||
| return False | ||
| if not self.isValidBST(root.right): | ||
| return False | ||
|
|
||
| return True | ||
|
|
||
| ``` | ||
|
|
||
| ## 再帰による解法 | ||
| --- | ||
| 左のノードに移動の場合は、上を上限、これまでの下限をそのまま下限、として進める。 | ||
|
|
||
| 時間計算量: O(N) | ||
| 空間計算量: O(N) | ||
|
|
||
| ### 1~2回目 | ||
| ```python | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
| def isValidBST_helper(node, left_value, right_value): | ||
| if not node: | ||
| return True | ||
|
|
||
| if not (left_value < node.val < right_value): | ||
| return False | ||
|
|
||
| return isValidBST_helper(node.left, left_value , node.val) and isValidBST_helper(node.right, node.val, right_value) | ||
|
|
||
| return isValidBST_helper(root, -float('inf'), float('inf')) | ||
| ``` | ||
|
|
||
| ### 3回目 | ||
| ```python | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
|
|
||
| def isValidBST_helper(node, lower_limit, upper_limit): | ||
| if not node: | ||
| return True | ||
| if not (lower_limit < node.val < upper_limit): | ||
| return False | ||
|
|
||
| return isValidBST_helper(node.left, lower_limit, node.val) and isValidBST_helper(node.right, node.val, upper_limit) | ||
|
|
||
| return isValidBST_helper(root, -float('inf'), float('inf')) | ||
| ``` | ||
|
|
||
|
|
||
| 再帰の解答を基にstackへの書き換えかなりスムーズにできた。 | ||
|
|
||
| ## スタックによる解法 | ||
| --- | ||
| 時間計算量: O(N) | ||
| 空間計算量: O(N) | ||
|
|
||
| ### 1~2回目 | ||
| ```python | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
| if not root: | ||
| return True | ||
|
|
||
| nodes_stack = [(root, -float('inf'), float('inf'))] | ||
| while nodes_stack: | ||
| for _ in range(len(nodes_stack)): | ||
| node, lower_limit, upper_limit = nodes_stack.pop() | ||
|
|
||
| if not (lower_limit < node.val < upper_limit): | ||
| return False | ||
|
|
||
| if node.left: | ||
| nodes_stack.append((node.left, lower_limit, node.val)) | ||
|
|
||
| if node.right: | ||
| nodes_stack.append((node.right, node.val, upper_limit)) | ||
|
|
||
| return True | ||
| ``` | ||
|
|
||
| ### 3回目 | ||
| ```python | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
| if not root: | ||
| return True | ||
|
|
||
| node_stack = [(root, -float('inf'), float('inf'))] | ||
|
|
||
| while node_stack: | ||
| node, lower_limit, upper_limit = node_stack.pop() | ||
| if not node: | ||
| continue | ||
|
|
||
| if not (lower_limit < node.val < upper_limit): | ||
| return False | ||
|
|
||
| node_stack.append((node.left, lower_limit, node.val)) | ||
| node_stack.append((node.right, node.val, upper_limit)) | ||
|
|
||
| return True | ||
| ``` | ||
|
|
||
| ## BFSによる解法 | ||
| 各ノードに関して左下、右下の値を確認する。 | ||
| dequeを利用すると、単純にpopleft()すればBFSになる。 | ||
| 部分的な書き換えのみのため、1回だけ解きました。 | ||
|
|
||
| 時間計算量: O(N) | ||
| 空間計算量: O(N) | ||
|
|
||
| ### 1回目 | ||
| ```python | ||
| class Solution: | ||
| def isValidBST(self, root: Optional[TreeNode]) -> bool: | ||
| if not root: | ||
| return True | ||
|
|
||
| node_stack = deque([(root, -float('inf'), float('inf'))]) | ||
|
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. 本当にstackですか?
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. ありがとうございます。ご指摘の通り、こちらqueueですね。 |
||
|
|
||
| while node_stack: | ||
| node, lower_limit, upper_limit = node_stack.popleft() | ||
| if not node: | ||
|
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. このタイミングで弾いても良いですが、自分ならnode_stackに追加するタイミングでNoneなら追加しないなーと思います。
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. そうですね、ノードを確認する量が1層分減りますね。この書き方であれば、 |
||
| continue | ||
|
|
||
| if not (lower_limit < node.val < upper_limit): | ||
| return False | ||
|
|
||
| node_stack.append((node.left, lower_limit, node.val)) | ||
| node_stack.append((node.right, node.val, upper_limit)) | ||
|
|
||
| return True | ||
| ``` | ||
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.
この条件は次checking_node.rightがpopされたときに判定されるので不要だと思いました。
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.
ありがとうございます。確かにそうですね。