-
Notifications
You must be signed in to change notification settings - Fork 0
98 validate binary search tree medium #29
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
base: main
Are you sure you want to change the base?
Conversation
docto-rin
left a comment
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.
いずれも非常に読みやすいと感じました。
またいろいろ試されてて良いと思います。
| is_valid, _, _ = find_validity_and_minmax(root) | ||
| return is_valid |
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.
return find_validity_and_minmax(root)[0] と書いてもいいですね。
| return True | ||
| if root.val <= lower or root.val >= upper: | ||
| return False | ||
| return is_valid(root.left, lower, root.val) and is_valid(root.right, root.val, upper) |
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.
この行ですが、インデント込みで97文字あるようです。
PEP8では一行あたりの文字数が79文字に制限されています。
Limit all lines to a maximum of 79 characters.
https://peps.python.org/pep-0008/#maximum-line-length
step3のように返り値を変数でおいてもいいですし、一応素朴には下記のように書くこともできます。
return (
is_valid(root.left, lower, root.val)
and is_valid(root.right, root.val, upper)
)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.
レビューとご指摘ありがとうございます。
確かに長すぎますね、Formatter/Linterをオフにしても長すぎると違和感を抱けるように気をつけます。
| if node is None: | ||
| continue |
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.
Noneチェックはpop後にやる他、append前にやる方法もあります。
一応速度の面ではappend前にやった方がわずか速いことになりますが、趣味の範囲だと思います。
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.
コメントありがとうございます。そうですね、自分もpop後にやる方がシンプルになると考えて、今回はこちらを採用しています。普段も基本的にはpop後にやる方を採用している気がします。
もしappend前にするなら、以下の場合にNoneのチェックが入ることになると思います。
left,rightの両方をappendする前rootがNoneの場合
多少コードが長くなっても、append前にNoneのチェックを書きたくなる場面としては、関数の引数の型をSomeType|Noneでなく、SomeTypeにしたい場合などでしょうか。
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.
totally agreeです!
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.
pop 後、append 前の比較ですが、基本的にはどちらでもいいと思います。
ただ、BFS で pop 後にフラグ立てると幾何級数的に増加することがあります。
https://discord.com/channels/1084280443945353267/1336510702742929499/1350740661791625327
同じ追記するべきかの判定が散らかるのに抵抗があるならば、関数化するのも一つでしょう。
| node, lower, upper = frontiers.pop() | ||
| if node is None: | ||
| continue | ||
| if lower >= node.val or upper <= node.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.
iterative_fifo.py のように
if not (lower < node.val node.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.
レビューありがとうございます。その通りですね。
| def find_validity_and_minmax(root: TreeNode) -> tuple[bool, int, int]: | ||
| min_val = max_val = root.val | ||
| if root.left is not None: | ||
| is_left_valid, min_val, left_max = find_validity_and_minmax(root.left) |
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.
先頭が be 同士だと関数名のように感じる人がいるかもしれません。 left_valid で十分だと思います。
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.
確かにその通りですね。名詞形の left_validity にまではしなくても良いのでしょうか。
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.
他の平均的なソフトウェアエンジニアが最短で正確に認知負荷少なく、違和感忌避感嫌悪感少なく理解できるのであれば良いと思います。他の方から left_validity のほうが良いというコメントをいただいたら、 left_validity にすれば十分だと思います。
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.
ありがとうございます!
問題へのリンク
98. Validate Binary Search Tree
言語
Python
自分の解法
step1
nをノード数とすると、O(n)O(n)hとするとO(h)。ただし、最悪の場合h = n。h深くなるため。O(log n)。テストケース
root = [2,1,3]->Trueroot = [5,1,4,null,null,3,6]->Falseroot = []->Trueroot = [1]->Trueroot = [2, null, 3]->Trueroot = [2, 1, null]->Trueroot = [1, 1, 2]->False、root = [2, 1, 2]->False木をテキストとして書く方法
lower/upperを用いた方法の方がシンプルに実装できる。二分木の走査方法としては、以下の3つがある。
step2
step3
lower/upperをlower_bound/upper_boundに変えたnot (lower < root.val < upper)に変えた。この方が読みやすいと思ったため。step4 (FB)
別解・模範解答
反復的な解法
rootから始めて、左右に進む際に、
lower/upperの制約を更新していく。ノードをpushした時点で、そのノードに対する制約(
lower/upper)は確定するので、ノードを取り出す順序はなんでも良い(スタックでもキューでもなんでも良い)。iterative_lifo.pyiterative_fifo.pyO(n)O(n)O(1)になるが、平衡木の場合はO(n)になる。n/2個入る可能性があるため。想定されるフォローアップ質問
次に解く問題の予告