Skip to content
Open
Show file tree
Hide file tree
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
43 changes: 43 additions & 0 deletions problems/98.validate-binary-search-tree/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## step1
- 最後にleft,rightに行った箇所が重要な気がした
- 常に下記を満たす必要がある
- 最後にleftに行った箇所のval未満でなければならない
- 最後にrightに行った箇所のvalを超える値でなければならない
- 幅優先探索をする
- 管理するnodeとless_than,more_thanを管理すれば良さそう
- NoneはTrueなのかFalseなのか
- `The number of nodes in the tree is in the range [1, 10^4].`となっているが、型はOptional
- 一旦Noneも入る想定にする
- 個人的にはFalseにしたい
- Trueの判定を行なった後でNoneのことを考慮したくない
- 10分ほどでかけた

## step2
- 再帰でも書ける気はする
- どれか1つでもFalseになったらダメなので`and`で繋いでいけば良い?
- 一旦書いてみる
- 10分ほどで書けたがhelperの子の有無をもっと上手く書けるかもしれない
- 数字の判定を先に書くことでFalseが入った場合に早めに打ち切られるようにした
- 他の人のコードを見る
- https://github.com/mamo3gr/arai60/pull/26
```
ところで `root is None` なときはどちらなんだろうか。もはや木ですらないし、比較する値もないが…。
→Geminiと議論したところ、空の木は二分探索木としてよいみたい。理屈としては、ノードがひとつだけの木を考えたとき、そのsubtreeも二分探索木なはずで、subtree=空の木だから。
Web上の資料を探してもらったが、明確に定義としてそう書いてあるものは見つけられなかった。
```
- 同じ部分が気にできていたが、結論は違っていた。`そのsubtreeも二分探索木なはず`これは確かに
- `何が分かりにくいかを言語化しておく。`こういう姿勢を持てるようになりたい
- `inf`をmath.infでも書けるのは知っておく
- https://github.com/huyfififi/coding-challenges/pull/39/changes#diff-ac2b937f26131bdaf8a2c0d3709d0befa4ae53c7efb9f6efbceb62567acc9c75
- `if node is None: continue`これは選択肢になかった。子がNoneの場合でも追加しておいて、チェックする際にcontinueする方法
- https://github.com/plushn/SWE-Arai60/pull/28/changes
- `yield_from`知らなかった
- https://docs.python.org/3.14/reference/expressions.html#grammar-token-python-grammar-yield_from
- 再帰に苦手意識があるので組み合わさると結構読む時に身構えてしまう
- https://github.com/Kaichi-Irie/leetcode-python/pull/29/changes
- `Noneチェックはpop後にやる他、append前にやる方法もあります。一応速度の面ではappend前にやった方がわずか速いことになりますが、趣味の範囲だと思います。pop後にやる方が大抵コードはシンプルになる気がします。`先ほどの気づきが一般化されて言語化されていた。このように言語化して理解していきたい。

## step3
- step1の変数名を修正した
- 処理時にNoneの判定をするようにした

42 changes: 42 additions & 0 deletions problems/98.validate-binary-search-tree/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#
# @lc app=leetcode id=98 lang=python3
#
# [98] Validate Binary Search Tree
#

# @lc code=start
# 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 isValidBST(self, root: Optional[TreeNode]) -> bool:
if root is None:
return False

more_than = -float("inf")
less_than = float("inf")
level_nodes_with_range = [(root, more_than, less_than)]

while level_nodes_with_range:
next_level_nodes_with_range = []
for node, more_than, less_than in level_nodes_with_range:
is_valid_bst_node = more_than < node.val < less_than

if not is_valid_bst_node:
return False

if node.left is not None:
next_level_nodes_with_range.append((node.left, more_than, node.val))
if node.right is not None:
next_level_nodes_with_range.append(
(node.right, node.val, less_than)
)
level_nodes_with_range = next_level_nodes_with_range

return True


# @lc code=end
40 changes: 40 additions & 0 deletions problems/98.validate-binary-search-tree/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#
# @lc app=leetcode id=98 lang=python3
#
# [98] Validate Binary Search Tree
#

# @lc code=start
# 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 isValidBST(self, root: Optional[TreeNode]) -> bool:
if root is None:
return False

def helper(node: TreeNode, more_than: int, less_than: int):
if node.left is None and node.right is None:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

step 2 で考察されていましたが、helperやqueueにNoneを積むのを許容して、またrootNoneの時Trueを返してしまえば、これらの場合分けは要らなくなりそうですね。

return more_than < node.val < less_than
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

https://github.com/xbam326/leetcode/pull/30/changes#r2829373715 のパターンがスッキリしそうですが、このままいくなら、何度も出てくる条件 more_than < node.val < less_than は変数に置くと分かり良いと思いました。

if node.left is None:
return more_than < node.val < less_than and helper(
node.right, node.val, less_than
)
if node.right is None:
return more_than < node.val < less_than and helper(
node.left, more_than, node.val
)

return (
more_than < node.val < less_than
and helper(node.right, node.val, less_than)
and helper(node.left, more_than, node.val)
)

return helper(root, -float("inf"), float("inf"))


# @lc code=end
41 changes: 41 additions & 0 deletions problems/98.validate-binary-search-tree/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#
# @lc app=leetcode id=98 lang=python3
#
# [98] Validate Binary Search Tree
#

# @lc code=start
# 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 isValidBST(self, root: Optional[TreeNode]) -> bool:
if root is None:
return True

more_than = -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.

min/max や low/high だと境界を含むように聞こえるから避けられたのだと予想しますが、more_than/less_than は少し動詞っぽい響きで、特定の値を示す時にはあまり使用されないように思います。
かといってここでバッチリ当てはまる変数も思いつかないので、難しいところですね 🤔

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

low/highとかlower/upperに _exclusive を付ける、のが正確性の面では良いと思いました(ちょっと長くなりますが)

less_than = float("inf")
current_level_nodes_with_range = [(root, more_than, less_than)]

while current_level_nodes_with_range:
next_level_nodes_with_range = []
for node, more_than, less_than in current_level_nodes_with_range:
if node is None:
continue

valid_bst_node = more_than < node.val < less_than
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

valid_bst_node だけ見ると TreeNode のように聞こえるので、is_valid_bst_node とした方が bool っぽさがでて良いかもですね。
The Art of Readable Code になんかそんな記述があったなと思って見返してみたのですが

In general, adding words like is, has, can, or should can make booleans more clear.

とありました。この練習会でも真偽値の変数名にこれらを使用される方を多くみますね。

if not valid_bst_node:
return False

next_level_nodes_with_range.append((node.left, more_than, node.val))
next_level_nodes_with_range.append((node.right, node.val, less_than))

current_level_nodes_with_range = next_level_nodes_with_range

return True


# @lc code=end