98. Validate Binary Search Tree(判断合法二叉搜索树)

验证二叉搜索树
本文探讨了如何判断一棵二叉树是否为有效的二叉搜索树(BST)。介绍了两种方法:一种是递归检查每个节点的值是否在其合法范围内;另一种是通过中序遍历来判断。同时分享了一个常见的错误解法及分析。
Given a binary tree, determine if it is a valid binary search tree (BST).

Assume a BST is defined as follows:

The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
Example 1:
    2
   / \
  1   3
Binary tree [2,1,3], return true.
Example 2:
    1
   / \
  2   3
Binary tree [1,2,3], return false.

我在这个问题上犯了个错误,一开始我仅仅把二叉树三个节点对比大小,可能造成二叉树局部三个节点符合BST树特性,但是放在全局就不符合了。因此我们要记录min_node和max_node,从顶层递归到下层。而不是从下层开始,仅仅因为三个节点满足就返回true。

典型情况:

    10
   /  \
  4    15
 / \   / \
2   5 6   17       

如上图,15,6,17局部满足BST树,但是6<10,所以不是BST树。

我的错误解法

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        return root != NULL ? is_bst(root) : true;
    }
    bool is_bst(TreeNode* root){
        if(root->left == NULL && root->right == NULL) return true;
        else if(root->left == NULL) return is_bst(root->right);
        else if(root->right == NULL) return is_bst(root->left);
        else return is_bst(root->left) && is_bst(root->right) 
                 && (root->left->val <= root->val && root->right->val > root->val);
    }
};

实际上错误解法通过了80%的case。

下面说正确解法方法一
利用BST树的特性,从上往下递归,记录min_node和max_node,对左子树来说,只需记录max_node,即它的父节点;同理对于右字数,只需记录min_node。然后它们满足BST关系即可。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        return root != NULL ? is_bst(root, NULL, NULL) : true;
    }
    bool is_bst(TreeNode* root, TreeNode* min_node, TreeNode* max_node){
        if(root == NULL)
            return true;
        if(min_node != NULL && root->val <= min_node->val || max_node != NULL && root->val >= max_node->val)
            return false;  //if false, stop and return
        return is_bst(root->left, min_node, root) && is_bst(root->right, root, max_node);
    }
};

方法二:利用中序遍历关系。由于BST树的中序遍历是有序的,所以我们用中序遍历来做文章。

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        TreeNode* prev = NULL;
        return is_bst(root, prev);
    }
    bool is_bst(TreeNode* root, TreeNode*& prev){
        if(root == NULL) return true;
        if(!is_bst(root->left, prev)) return false;
        if(prev != NULL && prev->val >= root->val) return false;
        prev = root;
        return is_bst(root->right, prev);
    }
};

利用prev节点一开始为NULL,后来作为中序遍历的前一个节点,和当前节点进行比较判断是否满足BST特性即可。

唉,人生苦短,我用Python :)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isValidBST(self, root):
        self.prev = None
        return self.is_bst(root, self.prev)

    def is_bst(self, root, prev):
        if root == None:
            return True
        if not self.is_bst(root.left, self.prev):
            return False
        if self.prev != None and self.prev.val >= root.val:
            return False
        self.prev = root
        return self.is_bst(root.right, self.prev)
### 如何用C语言实现对二叉搜索树判断 在C语言中,可以通过递归方法或者迭代方法来验证一棵给定的二叉是否满足二叉搜索树Binary Search Tree, BST)的特性。BST的核心属性在于:对于每一个节点而言,其左子中的所有节点值均小于该节点值,而右子中的所有节点值均大于该节点值。 #### 方法一:递归法 递归方法是最常见的解决方案之一。它通过维护一个范围 `[min_val, max_val]` 来确保每个节点都位于这个范围内。如果某个节点超出了允许的范围,则说明这不是一颗有效的BST[^1]。 以下是具体的代码实现: ```c #include <stdio.h> #include <stdlib.h> // 定义二叉节点结构体 typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; } TreeNode; int isValidBSTHelper(TreeNode* node, long min_val, long max_val) { if (node == NULL) return 1; // 如果到达叶子节点则返回true if ((long)node->val <= min_val || (long)node->val >= max_val) { return 0; // 节点超出有效范围 } // 对左右子分别进行递归检测 if (!isValidBSTHelper(node->left, min_val, node->val)) return 0; if (!isValidBSTHelper(node->right, node->val, max_val)) return 0; return 1; // 所有条件均满足时返回true } int is_valid_bst(TreeNode* root) { return isValidBSTHelper(root, LONG_MIN, LONG_MAX); } ``` 此代码片段定义了一个辅助函数 `isValidBSTHelper()` ,用于递归地检查每棵子是否符合BST的要求。 #### 方法二:中序遍历法 另一种常用的方法是利用 **中序遍历** 的特点——即如果按照从小到大的顺序访问整棵的话,那么最终获得的结果应该是一个严格单调递增数列[^2]。因此,在执行过程中只需记录上一次访问过的数值并将其与当前正在处理的数据做对比即可完成校验工作。 下面是基于上述原理编写的程序版本: ```c static int prev_value = INT_MIN; static _Bool first_call = 1; _Bool check_inorder(TreeNode* node){ if(!node)return true; if(!check_inorder(node->left))return false; if(first_call){first_call=0;} else{ if(prev_value>=node->val)return false; } prev_value=node->val; if(!check_inorder(node->right))return false; return true; } _Bool validate_BST(TreeNode* root){ first_call=1; return check_inorder(root); } ``` 这里引入了两个静态变量 `_prev_value_` 和 `_first_call_` 分别用来存储先前遇到的最大值以及标记首次调用状态以便初始化这些全局量[^5]。 --- ### 总结 以上两种算法各有优劣之处。前者时间复杂度较低但空间消耗较大;后者虽然不需要额外开辟栈内存却可能因为频繁修改外部共享资源而导致线程安全性问题。实际应用当中应视具体情况选择合适的技术路线。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值