# 0098. 验证二叉搜索树 ## 题目地址(98. 验证二叉搜索树) <https://leetcode-cn.com/problems/validate-binary-search-tree/> ## 题目描述 ``` <pre class="calibre18">``` 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数。 节点的右子树只包含大于当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 示例 1: 输入: 2 / \ 1 3 输出: true 示例 2: 输入: 5 / \ 1 4 / \ 3 6 输出: false 解释: 输入为: [5,1,4,null,null,3,6]。 根节点的值为 5 ,但是其右子节点值为 4 。 ``` ``` ## 前置知识 - 中序遍历 ## 公司 - 阿里 - 腾讯 - 百度 - 字节 ## 思路 ### 中序遍历 这道题是让你验证一棵树是否为二叉查找树(BST)。 由于中序遍历的性质`如果一个树遍历的结果是有序数组,那么他也是一个二叉查找树(BST)`, 我们只需要中序遍历,然后两两判断是否有逆序的元素对即可,如果有,则不是 BST,否则即为一个 BST。 ### 定义法 根据定义,一个结点若是在根的左子树上,那它应该小于根结点的值而大于左子树最小值;若是在根的右子树上,那它应该大于根结点的值而小于右子树最大值。也就是说,每一个结点必须落在某个取值范围: 1. 根结点的取值范围为(考虑某个结点为最大或最小整数的情况):(long\_min, long\_max) 2. 左子树的取值范围为:(current\_min, root.value) 3. 右子树的取值范围为:(root.value, current\_max) ## 关键点解析 - 二叉树的基本操作(遍历) - 中序遍历一个二叉查找树(BST)的结果是一个有序数组 - 如果一个树遍历的结果是有序数组,那么他也是一个二叉查找树(BST) ## 代码 ### 中序遍历 - 语言支持:JS,C++, Java JavaScript Code: ``` <pre class="calibre18">``` <span class="hljs-title">/* * @lc app=leetcode id=98 lang=javascript * * [98] Validate Binary Search Tree */</span> <span class="hljs-title">/** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */</span> <span class="hljs-title">/** * @param {TreeNode} root * @return {boolean} */</span> <span class="hljs-keyword">var</span> isValidBST = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">root</span>) </span>{ <span class="hljs-keyword">if</span> (root === <span class="hljs-params">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; <span class="hljs-keyword">if</span> (root.left === <span class="hljs-params">null</span> && root.right === <span class="hljs-params">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; <span class="hljs-keyword">const</span> stack = [root]; <span class="hljs-keyword">let</span> cur = root; <span class="hljs-keyword">let</span> pre = <span class="hljs-params">null</span>; <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">insertAllLefts</span>(<span class="hljs-params">cur</span>) </span>{ <span class="hljs-keyword">while</span> (cur && cur.left) { <span class="hljs-keyword">const</span> l = cur.left; stack.push(l); cur = l; } } insertAllLefts(cur); <span class="hljs-keyword">while</span> ((cur = stack.pop())) { <span class="hljs-keyword">if</span> (pre && cur.val <= pre.val) <span class="hljs-keyword">return</span> <span class="hljs-params">false</span>; <span class="hljs-keyword">const</span> r = cur.right; <span class="hljs-keyword">if</span> (r) { stack.push(r); insertAllLefts(r); } pre = cur; } <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; }; ``` ``` C++ Code: ``` <pre class="calibre18">``` <span class="hljs-title">// 递归</span> <span class="hljs-keyword">class</span> Solution { <span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">isValidBST</span><span class="hljs-params">(TreeNode* root)</span> </span>{ TreeNode* prev = <span class="hljs-params">nullptr</span>; <span class="hljs-keyword">return</span> validateBstInorder(root, prev); } <span class="hljs-keyword">private</span>: <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">validateBstInorder</span><span class="hljs-params">(TreeNode* root, TreeNode*& prev)</span> </span>{ <span class="hljs-keyword">if</span> (root == <span class="hljs-params">nullptr</span>) <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; <span class="hljs-keyword">if</span> (!validateBstInorder(root->left, prev)) <span class="hljs-keyword">return</span> <span class="hljs-params">false</span>; <span class="hljs-keyword">if</span> (prev != <span class="hljs-params">nullptr</span> && prev->val >= root->val) <span class="hljs-keyword">return</span> <span class="hljs-params">false</span>; prev = root; <span class="hljs-keyword">return</span> validateBstInorder(root->right, prev); } }; <span class="hljs-title">// 迭代</span> <span class="hljs-keyword">class</span> Solution { <span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">isValidBST</span><span class="hljs-params">(TreeNode* root)</span> </span>{ <span class="hljs-keyword">auto</span> s = <span class="hljs-params">vector</span><TreeNode*>(); TreeNode* prev = <span class="hljs-params">nullptr</span>; <span class="hljs-keyword">while</span> (root != <span class="hljs-params">nullptr</span> || !s.empty()) { <span class="hljs-keyword">while</span> (root != <span class="hljs-params">nullptr</span>) { s.push_back(root); root = root->left; } root = s.back(); s.pop_back(); <span class="hljs-keyword">if</span> (prev != <span class="hljs-params">nullptr</span> && prev->val >= root->val) <span class="hljs-keyword">return</span> <span class="hljs-params">false</span>; prev = root; root = root->right; } <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; } }; ``` ``` Java Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>{ <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isValidBST</span><span class="hljs-params">(TreeNode root)</span> </span>{ Stack<Integer> stack = <span class="hljs-keyword">new</span> Stack<> (); TreeNode previous = <span class="hljs-keyword">null</span>; <span class="hljs-keyword">while</span> (root != <span class="hljs-keyword">null</span> || !stack.isEmpty()) { <span class="hljs-keyword">while</span> (root != <span class="hljs-keyword">null</span>) { stack.push(root); root = root.left; } root = stack.pop(); <span class="hljs-keyword">if</span> (previous != <span class="hljs-keyword">null</span> && root.val <= previous.val ) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; previous = root; root = root.right; } <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>; } } ``` ``` ### 定义法 - 语言支持:C++,Python3, Java, JS C++ Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */</span> <span class="hljs-title">// 递归</span> <span class="hljs-keyword">class</span> Solution { <span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">isValidBST</span><span class="hljs-params">(TreeNode* root)</span> </span>{ <span class="hljs-keyword">return</span> helper(root, LONG_MIN, LONG_MAX); } <span class="hljs-keyword">private</span>: <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">helper</span><span class="hljs-params">(<span class="hljs-keyword">const</span> TreeNode* root, <span class="hljs-keyword">long</span> min, <span class="hljs-keyword">long</span> max)</span> </span>{ <span class="hljs-keyword">if</span> (root == <span class="hljs-params">nullptr</span>) <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; <span class="hljs-keyword">if</span> (root->val >= max || root->val <= min) <span class="hljs-keyword">return</span> <span class="hljs-params">false</span>; <span class="hljs-keyword">return</span> helper(root->left, min, root->val) && helper(root->right, root->val, max); } }; <span class="hljs-title">// 循环</span> <span class="hljs-keyword">class</span> Solution { <span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">isValidBST</span><span class="hljs-params">(TreeNode* root)</span> </span>{ <span class="hljs-keyword">if</span> (root == <span class="hljs-params">nullptr</span>) <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; <span class="hljs-keyword">auto</span> ranges = <span class="hljs-params">queue</span><pair<<span class="hljs-keyword">long</span>, <span class="hljs-keyword">long</span>>>(); ranges.push(make_pair(LONG_MIN, LONG_MAX)); <span class="hljs-keyword">auto</span> nodes = <span class="hljs-params">queue</span><<span class="hljs-keyword">const</span> TreeNode*>(); nodes.push(root); <span class="hljs-keyword">while</span> (!nodes.empty()) { <span class="hljs-keyword">auto</span> sz = nodes.size(); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> i = <span class="hljs-params">0</span>; i < sz; ++i) { <span class="hljs-keyword">auto</span> range = ranges.front(); ranges.pop(); <span class="hljs-keyword">auto</span> n = nodes.front(); nodes.pop(); <span class="hljs-keyword">if</span> (n->val >= range.second || n->val <= range.first) { <span class="hljs-keyword">return</span> <span class="hljs-params">false</span>; } <span class="hljs-keyword">if</span> (n->left != <span class="hljs-params">nullptr</span>) { ranges.push(make_pair(range.first, n->val)); nodes.push(n->left); } <span class="hljs-keyword">if</span> (n->right != <span class="hljs-params">nullptr</span>) { ranges.push(make_pair(n->val, range.second)); nodes.push(n->right); } } } <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; } }; ``` ``` Python Code: ``` <pre class="calibre18">``` <span class="hljs-title"># Definition for a binary tree node.</span> <span class="hljs-title"># class TreeNode:</span> <span class="hljs-title"># def __init__(self, x):</span> <span class="hljs-title"># self.val = x</span> <span class="hljs-title"># self.left = None</span> <span class="hljs-title"># self.right = None</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span>:</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">isValidBST</span><span class="hljs-params">(self, root: TreeNode, area: tuple=<span class="hljs-params">(-float<span class="hljs-params">(<span class="hljs-string">'inf'</span>)</span>, float<span class="hljs-params">(<span class="hljs-string">'inf'</span>)</span>)</span>)</span> -> bool:</span> <span class="hljs-string">"""思路如上面的分析,用Python表达会非常直白 :param root TreeNode 节点 :param area tuple 取值区间 """</span> <span class="hljs-keyword">if</span> root <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>: <span class="hljs-keyword">return</span> <span class="hljs-keyword">True</span> is_valid_left = root.left <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span> <span class="hljs-keyword">or</span>\ (root.left.val < root.val <span class="hljs-keyword">and</span> area[<span class="hljs-params">0</span>] < root.left.val < area[<span class="hljs-params">1</span>]) is_valid_right = root.right <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span> <span class="hljs-keyword">or</span>\ (root.right.val > root.val <span class="hljs-keyword">and</span> area[<span class="hljs-params">0</span>] < root.right.val < area[<span class="hljs-params">1</span>]) <span class="hljs-title"># 左右节点都符合,说明本节点符合要求</span> is_valid = is_valid_left <span class="hljs-keyword">and</span> is_valid_right <span class="hljs-title"># 递归下去</span> <span class="hljs-keyword">return</span> is_valid\ <span class="hljs-keyword">and</span> self.isValidBST(root.left, (area[<span class="hljs-params">0</span>], root.val))\ <span class="hljs-keyword">and</span> self.isValidBST(root.right, (root.val, area[<span class="hljs-params">1</span>])) ``` ``` Java Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>{ <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isValidBST</span><span class="hljs-params">(TreeNode root)</span> </span>{ <span class="hljs-keyword">return</span> helper(root, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>); } <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">helper</span><span class="hljs-params">(TreeNode root, Integer lower, Integer higher)</span> </span>{ <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>; <span class="hljs-keyword">if</span> (lower != <span class="hljs-keyword">null</span> && root.val <= lower) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; <span class="hljs-keyword">if</span> (higher != <span class="hljs-keyword">null</span> && root.val >= higher) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; <span class="hljs-keyword">if</span> (!helper(root.left, lower, root.val)) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; <span class="hljs-keyword">if</span> (!helper(root.right, root.val, higher)) <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>; } } ``` ``` JavaScript Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */</span> <span class="hljs-title">/** * @param {TreeNode} root * @return {boolean} */</span> <span class="hljs-keyword">var</span> isValidBST = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">root</span>) </span>{ <span class="hljs-keyword">if</span> (!root) <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; <span class="hljs-keyword">return</span> valid(root); }; <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">valid</span>(<span class="hljs-params">root, min = -Infinity, max = Infinity</span>) </span>{ <span class="hljs-keyword">if</span> (!root) <span class="hljs-keyword">return</span> <span class="hljs-params">true</span>; <span class="hljs-keyword">const</span> val = root.val; <span class="hljs-keyword">if</span> (val <= min) <span class="hljs-keyword">return</span> <span class="hljs-params">false</span>; <span class="hljs-keyword">if</span> (val >= max) <span class="hljs-keyword">return</span> <span class="hljs-params">false</span>; <span class="hljs-keyword">return</span> valid(root.left, min, val) && valid(root.right, val, max); } ``` ``` **复杂度分析** - 时间复杂度:O(N)O(N)O(N) - 空间复杂度:O(N)O(N)O(N) ## 相关题目 [230.kth-smallest-element-in-a-bst](230.kth-smallest-element-in-a-bst.html) 大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:<https://github.com/azl397985856/leetcode> 。 目前已经 37K star 啦。 大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。 ![](https://img.kancloud.cn/cf/0f/cf0fc0dd21e94b443dd8bca6cc15b34b_900x500.jpg)