問題
二分木のroot を
- 左の
部分木に ある 値は、 どれも その節の 値より小さい - 右の
部分木に ある 値は、 どれも その節の 値より大きい - 同じ値は
許しません。 同じ 値が 2 つ あれば偽です
各節は val (値)、left (左のright (右のNone、null、nil です。TreeNode で、Val、Left、Right と
例では、null です。
入力と出力の例
例 1
根が 8、
入力
root = [8, 3, 12, 1, 6, 10, 15]出力
true例 2
3 の
入力
root = [8, 3, 12, 1, 9]出力
false例 3
左の
入力
root = [5, 5]出力
false面接での聞かれ方
面接では、
- 「この
二分木が、 正しい 二分探索木か どうかを 判定してください」 - 親と
子だけを 比べる 書き方を 出すと、 例 2 のような 木を 示して 「これは どうなりますか?」と 聞かれます - 書き終えた
あとに 「中順 (左、 自分、 右の 順) に たどる 書き方でも 書けますか?」 「同じ値を 左に 許す決まりなら どこを 変えますか?」と 広げて 聞かれます
同じ値を
アルゴリズムのチートシートの「再帰と木」に、この型の要点を表とコードでまとめています。
まず 考える手順
段 1
まず浮かぶのは、
段 2
見方を
段 3
関数は (節, 下の限り, 上の限り) を
段 4
別の
解答
Python
Python
def is_search_tree(root):
inf = float("inf")
return walk(root, -inf, inf)
def walk(n, lo, hi):
if n is None:
return True
v = n.val
if not lo < v < hi:
return False
if not walk(n.left, lo, v):
return False
return walk(n.right, v, hi)JavaScript
JavaScript
function isSearchTree(root) {
const inf = Infinity;
return walk(root, -inf, inf);
}
function walk(n, lo, hi) {
if (n === null) {
return true;
}
const v = n.val;
if (v <= lo || v >= hi) {
return false;
}
if (!walk(n.left, lo, v)) {
return false;
}
return walk(n.right, v, hi);
}Go
Go
import "math"
func isSearchTree(
root *TreeNode,
) bool {
lo := math.MinInt
hi := math.MaxInt
return walk(root, lo, hi)
}
func walk(
n *TreeNode, lo, hi int,
) bool {
if n == nil {
return true
}
v := n.Val
if v <= lo || v >= hi {
return false
}
if !walk(n.Left, lo, v) {
return false
}
return walk(n.Right, v, hi)
}最初のint のint の
計算量
- 時間は O(n) です。
どの 節にも 1 回ずつ 行き、 限りとの 比べを 1 回します - 使う
記憶は O(h) です。 h は 木の 高さで、 再帰の 呼び出しが 深さの 分だけ積まれます。 1 本道の 木では O(n) に なります。 節が 500 以下なので、 Python の 再帰の 上限 (1000 段) には 届きません
よく ある間違い
- 親と
子だけを比べる。 例 2 のように、 親とは 合っていても 祖先との 決まりを 破る 値を 見落とします。 範囲を 上から 渡すか、 中順で 全体の 並びを見ます - 限りの
比べに 等号を 入れ忘れる。 v < loやv > hiと書くと、 例 3 のように 同じ値を 許してしまいます。 この 問題は 同じ値を 許さないので、 v <= loとv >= hiで偽にします - 最初の
限りを 値の 範囲の 端にする。 32 ビットの 最小値 -2147483648 を 下の 限りに すると、 ちょうど その値の 節が 「限りと同じ」と 見られて偽に なります。 値の 範囲より 外の 数 (無限大や 64 ビットの 端) を使います - 深い木で
再帰の 上限に当たる。 節が もっと 多く 1 本道に 近い木なら、 Python は 再帰の 上限で 止まります。 その 大きさを 聞かれたら、 スタックを 使って 中順に たどる 繰り返しの 書き方に すると答えます
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.6確認日 2026年10月30日
面接での 話し方の例
書き始める
「親と
子だけを 比べると、 祖先との 決まりを 破る 値を 見落とします。 根から 下へ 進むたびに 入って よい 値の 範囲が 狭まるので、 下の 限りと 上の 限りを 引数で 渡す再帰にします。 左へ 進むときは 上の 限りを、 右へ 進むときは 下の 限りを 自分の 値に 替えます。 同じ値は 許さないので、 端は 含めずに 比べます。 時間は O(n)、 記憶は 木の 高さの 分です。」
書き終えたら、
「例 2 で
たどります。 根 8 は 限り無しで 通ります。 左の 3 は 上の 限りが 8 で 通ります。 3 の 右の 9 には、 下の 限り 3 と 上の 限り 8 が 渡ります。 9 は 8 以上 なので、 ここで 偽を 返します。」
