验证二叉搜索树
Category | Difficulty | Likes | Dislikes |
---|---|---|---|
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题做过生成二分查找树。二分查找树定义如下:
- 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
- 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点。
解法一
开始的时候以为可以很简单的用递归写出来。想法是,左子树是合法二分查找树,右子树是合法二分查找树,并且根节点大于左孩子,小于右孩子,那么当前树就是合法二分查找树。
当然,这个解法没有通过。对于下面的测试用例,这种解法是错误的。
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; } };