diff --git "a/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/98. Validate Binary Search Tree.md" "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/98. Validate Binary Search Tree.md" new file mode 100644 index 0000000..4ebba68 --- /dev/null +++ "b/\347\253\266\346\212\200\343\203\227\343\203\255\345\260\261\346\264\273\351\203\250PR\347\224\250/98. Validate Binary Search Tree.md" @@ -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'))]) + + while node_stack: + node, lower_limit, upper_limit = node_stack.popleft() + 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 +```