Swift教室 Swift と競技プログラミングの教室

28. Validate Binary Search Tree

読了目安 約2分

Tree / LC 98 (Medium) — BST の検証。値の範囲を上から伝える再帰。

この章の目次

問題

LeetCode 98. Validate Binary Search Tree(Medium / カテゴリ: Tree)

二分木の根 root が与えられるので、正しい二分探索木(BST)かを判定します。 条件は、各ノードについて「左の部分木のすべての値 < ノードの値 < 右の部分木のすべての値」です。 等しい値は許されません。 このページのテストでは、ノードの値として Int.minInt.max も現れます。

考え方

ヒント 1

「左の子 < 親 < 右の子」を各ノードで確かめるだけでは足りません。 [5, 1, 4, nil, nil, 3, 6] のように、右の部分木の奥に親より小さい値が隠れている反例があります。

ヒント 2

各ノードが取り得る値の範囲(下限, 上限)を根から伝えます。 左に降りるときは上限をそのノードの値に、右に降りるときは下限をそのノードの値に狭めます。 別解として、中間順走査の列が真に昇順(等しい値なし)かを確かめる方法もあります。

Swift 実装のポイント

  • 下限・上限を Int.min / Int.max の番兵で初期化すると、ノードの値がちょうど Int.min / Int.max のときに誤判定します。範囲は Int? で持ち、nil を「制限なし」と扱うのが安全です。
  • 比較は「下限 < 値 < 上限」の狭義の不等号です。等しい値は BST に許されません。
  • if let low = low, node.val <= low { return false } の形で、オプショナルの下限を自然に検査できます。
模範解答
Swift
class Solution {
    func isValidBST(_ root: TreeNode?) -> Bool {
        func valid(_ node: TreeNode?, _ low: Int?, _ high: Int?) -> Bool {
            guard let node = node else { return true }
            if let low = low, node.val <= low { return false }
            if let high = high, node.val >= high { return false }
            return valid(node.left, low, node.val) && valid(node.right, node.val, high)
        }
        return valid(root, nil, nil)
    }
}

計算量: O(N)。各ノードを 1 回ずつ検査します。