LeetCode98:验证二叉搜索树(多解)

题目LeetCode98

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含严格小于当前节点的数。
  • 节点的右子树只包含 严格大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树

示例

**输入:**root = 2,1,3

**输出:**true

Python解法

解法一(递归)

python 复制代码
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        # 辅助函数:检查以node为根的子树是否在(low, high)这个区间内
        def check(node, must_greater_than, must_less_than):
            # 情况1:节点是空的,说明这条路径没问题,返回True
            if not node:
                return True
            
            # 情况2:节点不满足"必须大于左边的数"
            if must_greater_than is not None and node.val <= must_greater_than:
                return False
            
            # 情况3:节点不满足"必须小于右边的数"
            if must_less_than is not None and node.val >= must_less_than:
                return False
            
            # 检查左子树:
            #  左子树所有节点都必须 < 当前节点值
            #  同时左子树所有节点都要继承"必须大于的数"
            left_ok = check(node.left, must_greater_than, node.val)
            
            # 检查右子树:
            #  右子树所有节点都必须 > 当前节点值
            #  同时右子树所有节点都要继承"必须小于的数"
            right_ok = check(node.right, node.val, must_less_than)
            
            # 左右都没问题,整棵子树才是合法的
            return left_ok and right_ok
        
        # 根节点一开始没有任何限制:
        #  没有"必须大于谁",也没有"必须小于谁"
        return check(root, None, None)

解法二(中序遍历)

python 复制代码
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        stack = []
        prev = float('-inf')  # 记录中序遍历的前一个节点值

        # 中序遍历的标准迭代写法:左-根-右
        while stack or root:
            # 1. 一路往左走,把所有左节点压入栈
            while root:
                stack.append(root)
                root = root.left
            
            # 2. 取出栈顶节点(此时是当前最左未访问的节点)
            root = stack.pop()

            # 3. 核心判断:当前节点值必须严格大于前一个节点值
            if root.val <= prev:
                return False
            prev = root.val  # 更新前一个节点值为当前值

            # 4. 转向右子树(下一轮继续处理右子树的左分支)
            root = root.right
        
        return True

过程展示

Java解法

解法一(递归)

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        return check(root, null, null);
    }

    /**
     * @param node 当前要检查的节点
     * @param mustGreaterThan 当前节点必须大于这个值(可以为 null,表示无下限)
     * @param mustLessThan 当前节点必须小于这个值(可以为 null,表示无上限)
     */
    private boolean check(TreeNode node, Integer mustGreaterThan, Integer mustLessThan) {
        // 空节点默认合法
        if (node == null) {
            return true;
        }

        // 不满足下限限制
        if (mustGreaterThan != null && node.val <= mustGreaterThan) {
            return false;
        }
        // 不满足上限限制
        if (mustLessThan != null && node.val >= mustLessThan) {
            return false;
        }

        // 左子树:上限变成当前节点值,下限继承
        boolean leftOk = check(node.left, mustGreaterThan, node.val);
        // 右子树:下限变成当前节点值,上限继承
        boolean rightOk = check(node.right, node.val, mustLessThan);

        return leftOk && rightOk;
    }
}

解法二(中序遍历)

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        long prev = Long.MIN_VALUE; // 用 long 避免 int 边界溢出

        while (!stack.isEmpty() || root != null) {
            // 一路向左走,全部入栈
            while (root != null) {
                stack.push(root);
                root = root.left;
            }

            // 弹出节点
            root = stack.pop();

            // 核心判断:必须严格递增
            if (root.val <= prev) {
                return false;
            }
            prev = root.val;

            // 走向右子树
            root = root.right;
        }
        return true;
    }
}

C++解法

解法一(递归)

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        return check(root, nullptr, nullptr);
    }

private:
    /**
     * @param node 当前节点
     * @param mustGreaterThan 当前节点必须大于这个值(可以为 nullptr,表示无下限)
     * @param mustLessThan 当前节点必须小于这个值(可以为 nullptr,表示无上限)
     */
    bool check(TreeNode* node, int* mustGreaterThan, int* mustLessThan) {
        if (!node) {
            return true;
        }

        // 不满足下限限制
        if (mustGreaterThan != nullptr && node->val <= *mustGreaterThan) {
            return false;
        }
        // 不满足上限限制
        if (mustLessThan != nullptr && node->val >= *mustLessThan) {
            return false;
        }

        // 左子树:上限变成当前节点值,下限继承
        bool leftOk = check(node->left, mustGreaterThan, &(node->val));
        // 右子树:下限变成当前节点值,上限继承
        bool rightOk = check(node->right, &(node->val), mustLessThan);

        return leftOk && rightOk;
    }
};

解法二(中序遍历)

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        stack<TreeNode*> stack;
        long prev = LONG_MIN; // 避免 int 边界问题

        while (!stack.empty() || root != nullptr) {
            // 一路向左走,全部入栈
            while (root != nullptr) {
                stack.push(root);
                root = root->left;
            }

            // 弹出节点
            root = stack.top();
            stack.pop();

            // 核心判断
            if (root->val <= prev) {
                return false;
            }
            prev = root->val;

            // 走向右子树
            root = root->right;
        }
        return true;
    }
};
相关推荐
夏幻灵5 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
程序猿编码5 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
bkspiderx7 小时前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
代码什么用7 小时前
Spring基础使用
java·后端·spring
程序员老陆7 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
沐晓时光7 小时前
C语言入门,深入理解指针(3)
c语言·开发语言
信奥卷王7 小时前
[GESP202609 六级] 分树规划
算法
Su米苏7 小时前
Spring AI 中MCP 与普通 @Tool的区别
java·人工智能·spring
夏幻灵7 小时前
LeetCode 21:合并两个有序链表——双指针与哑节点详解
算法·leetcode·链表
码云数智-园园8 小时前
unique_ptr 还是 shared_ptr?C++ 智能指针选型与内存泄漏实战分析
java·开发语言