[LeetCode] 98. Validate Binary Search Tree 验证二叉搜索树

验证二叉搜索树

CategoryDifficultyLikesDislikes
algorithms Medium (31.28%) 620 -

TagsCompanies

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

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

示例 1:

输入:
    2
   / \
  1   3
输出: true

 

示例 2:

输入:
    5
   / \
  1   4
     / \
    3   6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
     根节点的值为 5 ,但是其右子节点值为 4 。

输入一个树,判断该树是否是合法的二分查找树(二叉搜索树),95题做过生成二分查找树。二分查找树定义如下:

  1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点。

解法一

    开始的时候以为可以很简单的用递归写出来。想法是,左子树是合法二分查找树,右子树是合法二分查找树,并且根节点大于左孩子,小于右孩子,那么当前树就是合法二分查找树。

当然,这个解法没有通过。对于下面的测试用例,这种解法是错误的。

  10

     / \

   5 15
     / \
    6 20

   虽然满足左子树是合法二分查找树,右子树是合法二分查找树,并且根节点大于左孩子,小于右孩子,但这个树不是合法的二分查找树。因为右子树中的 6 小于当前根节点 10。

   所以我们不应该判断「根节点大于左孩子,小于右孩子」,而是判断「根节点大于左子树中最大的数,小于右子树中最小的数」。

   正确代码如下:

   

 1 class Solution {
 2 public:
 3     bool isValidBST(TreeNode* root)//二叉树的中序遍历
 4     {  
 5          //递归出口
 6         if(!root) return true;
 7         //搜索二叉树中根结点应小于左子树的最右边节点(左子树最大值),大于右子树的最左边节点(右子树最小值)
 8         bool root_valid = false;
 9         TreeNode* most_left_ptr = root->left; //左子树的最右节点(左子树最大值)
10         TreeNode* most_right_ptr = root->right; //右子树的最左节点(右子树最小值)
11         //走到最右求左子树最大值
12         TreeNode* workPtr = most_left_ptr;
13         while(workPtr)
14         {
15             most_left_ptr = workPtr;
16             workPtr = workPtr->right;
17         }
18         //走到最左求右子树最小值
19         workPtr = most_right_ptr;
20         while(workPtr)
21         {
22             most_right_ptr = workPtr;
23             workPtr = workPtr->left;
24         }
25 
26         if(most_left_ptr&&most_right_ptr)//左右子树都非空
27         {
28             root_valid = root->val>most_left_ptr->val&&root->val<most_right_ptr->val;
29         }
30         else if(most_left_ptr)//左非空、右空
31         {
32             root_valid = root->val>most_left_ptr->val;
33         }
34         else if(most_right_ptr)//左空,右非空
35         {
36             root_valid = root->val<most_right_ptr->val;
37         }
38         else//当前根节点是叶子节点
39         {
40             root_valid = true;
41         }
42        //递归地对左右子树做同样的判断
43         bool left_valid = isValidBST(root->left);
44         bool right_valid = isValidBST(root->right);
45         
46         return root_valid&&left_valid&&right_valid;
47     }
48 };

 解法二:

    解法一中,我们是判断根节点是否合法,找到了左子树中最大的数,右子树中最小的数。 由左子树和右子树决定当前根节点是否合法。

但如果正常的来讲,明明先有的根节点,按理说根节点是任何数都行,而不是由左子树和右子树限定。相反,根节点反而决定了左孩子和右孩子

的合法取值范围。所以,我们可以从根节点进行 DFS,然后计算每个节点应该的取值范围,如果当前节点不符合就返回 false。

代码如下:

class Solution {
public:
    bool isValidBST(TreeNode* root)//二叉树的中序遍历
    {  
        //最小、最大整数取 INT_MIN 和 INT_MAX会有测试用例通不过
         long int low = LONG_MIN;
         long int high = LONG_MAX;
         return helper(root,low, high);
    }
    bool helper(TreeNode* root,long int low, long int high)
    {
        if(!root) return true;
        int value  = root->val;
        if(value<=low || value>=high) return false;
        bool left_valid = helper(root->left,low,value);
        bool right_valid = helper(root->right,value,high);
        return left_valid&&right_valid;
    }
};

 

posted @ 2020-06-16 00:24  谁在写西加加  阅读(98)  评论(0编辑  收藏  举报