Conversation
huyfififi
left a comment
There was a problem hiding this comment.
全てのコードがわかりやすかったです。Dartのシンタックスを調べる良い機会になりました!
| class Solution { | ||
| bool isValidBST(TreeNode? root) { | ||
| num previousValue = double.negativeInfinity; | ||
|
|
||
| bool isValidBSTInorderTraverse(TreeNode? node) { | ||
| if (node == null) { | ||
| return true; | ||
| } | ||
|
|
||
| if (!isValidBSTInorderTraverse(node.left)) { | ||
| return false; | ||
| } | ||
|
|
||
| if (node.val <= previousValue) { | ||
| return false; | ||
| } | ||
| previousValue = node.val; | ||
|
|
||
| return isValidBSTInorderTraverse(node.right); | ||
| } | ||
|
|
||
| return isValidBSTInorderTraverse(root); | ||
| } | ||
| } |
There was a problem hiding this comment.
以下の2点がちょっとトリッキーに感じました。
- ヘルパー関数の外側にある
previousValueを使って「前」の値を保存しておく - 左右の子を辿る途中で、昇順かどうかのチェックをしている
個人的には、inorderで値を取り出すところと、昇順かチェックするところは分離する方が読みやすいと思いました。以下はGeminiに生成させたものなのでdart的な良し悪しはわかりませんがご参考まで。
class Solution {
bool isValidBST(TreeNode? root) {
if (root == null) return true;
Iterable<int> traverseInorder(TreeNode? node) sync* {
if (node == null) return;
yield* traverseInorder(node.left);
yield node.val;
yield* traverseInorder(node.right);
}
num previousValue = double.negativeInfinity;
for (final currentValue in traverseInorder(root)) {
if (currentValue <= previousValue) {
return false;
}
previousValue = currentValue;
}
return true;
}
}There was a problem hiding this comment.
参考コードありがとうございます。確かに分離する方が読みやすいですね。
ノード数がかなり大きい場合は、時間やメモリを節約する上で分離しない手法を選択するみたいな使い分けが良いと思っています。
| final isLarger = min < node.val; | ||
| final isSmaller = node.val < max; | ||
|
|
||
| if (!isLarger || !isSmaller) { |
There was a problem hiding this comment.
変数に置きすぎで、数直線上に並べるくらいでも十分伝わりそうです。
| final isLarger = min < node.val; | |
| final isSmaller = node.val < max; | |
| if (!isLarger || !isSmaller) { | |
| if (!(min < node.val && node.val < max)) { |
| var nodesWithLimits = <(TreeNode, num, num)>[ | ||
| (root, double.negativeInfinity, double.infinity), | ||
| ]; |
There was a problem hiding this comment.
(単に、個人の好みの表明です)
初期値の設定やpopのときに何が入っているか分かるので、このスタック(場合によってはキュー)には stack 以上の情報を持たせてもさほど意味は無いんじゃないかな(むしろ複雑な名前がノイジーになるのでは)、と最近感じるようになりました。
There was a problem hiding this comment.
レビューありがとうございます。
練習会を進めていく上で考えが変わるかもしれませんが、名前に情報は持たせておいた方がいいのではないかなと個人的には思います。例えば、一年後に、この関数を作成した背景を忘れた状況で、スタックやキューの中身から役割を類推するのが意外に難しそうと感じるのと、人によって変数の役割の理解が異なってしまったときに、勘違いが起こりミスにつながりそうと感じるためです。
解いた問題:https://leetcode.com/problems/validate-binary-search-tree/description/
次に解く問題:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/