Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 240 additions & 0 deletions 競技プロ就活部PR用/98. Validate Binary Search Tree.md
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
Comment on lines +27 to +28
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この条件は次checking_node.rightがpopされたときに判定されるので不要だと思いました。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。確かにそうですね。

# 右側ノードから見た時の、左側の脛手の値をチェックするため、
# 右側のノードを親ノード見立ててチェックするため、加える。
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'))])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本当にstackですか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。ご指摘の通り、こちらqueueですね。
また、node_stackよりは、nodes_and_boundsとかの方が良いかと思いました。


while node_stack:
node, lower_limit, upper_limit = node_stack.popleft()
if not node:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

このタイミングで弾いても良いですが、自分ならnode_stackに追加するタイミングでNoneなら追加しないなーと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

そうですね、ノードを確認する量が1層分減りますね。この書き方であれば、
if not root: return Trueを削除しても動くと思ったですが、消し忘れてますね。

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
```