LeetCode第[98]题(Java):Validate Binary Search Tree(验证二叉搜索树)
题目:验证二叉搜索树
难度:Medium
题目内容:
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.
翻译:
给定一棵二叉树,确定它是否是一个有效的二叉搜索树(BST)。
BST的定义如下:
节点的左子树只包含小于节点键的键节点。
节点的右子树只包含大于节点键的键节点。
左和右子树都必须是二叉搜索树。
Example 1:
Input: 2 / \ 1 3 Output: true
Example 2:
5 / \ 1 4 / \ 3 6 Output: false
我的思路:搜索二叉树的验证就是要求每一个子树都是满足搜索树的“左小右大”的规定,
1、先判断自己作为根节点的左右二叉是否符合;
2、然后返回左右节点的递归结果的 “与” (全都符合才算符合)
我的代码:
1 public boolean isValidBST(TreeNode root) { 2 if (root == null) { 3 return true; 4 } 5 6 if (root.left != null) { 7 TreeNode cur = root.left; 8 while (cur.right != null) { 9 cur = cur.right; 10 } 11 if (cur.val >= root.val) { 12 return false; 13 } 14 } 15 16 if (root.right != null) { 17 TreeNode cur = root.right; 18 while (cur.left != null) { 19 cur = cur.left; 20 } 21 if (cur.val <= root.val) { 22 return false; 23 } 24 } 25 26 return isValidBST(root.left) && isValidBST(root.right); 27 }
我的复杂度:O(N*logN)
编码过程中的问题:
1、没仔细看题,而且记错搜索树的定义了,当出现两个值相等的时候,此时不是搜索树;
2、最开始只考虑到判断根节点和左右两个子节点就行了,结果后面案例跑错了,例如:
5 / \ 1 6 / \ 3 7 每个子树都是正确的二叉搜索树,但是整体上看,5的右子树内有比它小的3,所以此树不是二叉搜索树。
此时想到二叉树删除算法,当删除节点有两个子节点的时候,此时会选择此节点左节点的最右子系节点,或者右节点的最左子系节点进行代替,所以这两个节点值才是最接近根节点值的节点,所以每次的单个子树判断应该判断这两个,而不是左右子节点就行了。
答案代码:
1 public boolean isValidBST(TreeNode root) { 2 return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE); 3 } 4 5 public boolean isValidBST(TreeNode root, long minVal, long maxVal) { 6 if (root == null) return true; 7 if (root.val >= maxVal || root.val <= minVal) return false; 8 return isValidBST(root.left, minVal, root.val) && isValidBST(root.right, root.val, maxVal); 9 }
答案复杂度:O(N)
答案思路:
也是利用了递归的思想,分别对每一个子树进行判断,但是它的亮点在于在判断的时候并不需要对子树进行搜索“最相近的值”,而是利用了“最大值”、“最小值”的思想:
对于每个子树,都有一个最大值和一个最小值,
对于左子树,最大值就是它的根节点的值,最小值是根节点的最小值(左父亲或者MIN_VALUE)
对于右子树,最小值就是它的根节点的值,最大值是根节点的最大值(右父亲或者MAX_VALUE)
例如:
5 / \ 1 6 / \ 3 7
5的满足小于最大值,大于最小值,然后递归(1,MIN,5) && 递归(4,5,MAX)
。。。
3节点的最大值为6,最小值应该为5,此时不满足,所以return false
其实还有一种非递归的解法:中序遍历,利用二叉搜索树中序遍历的有序性(在中序遍历的出栈时判断此值是否小于之前出栈的那个节点的值)
1 public boolean isValidBST(TreeNode root) { 2 if (root == null) return true; 3 Stack<TreeNode> stack = new Stack<>(); 4 TreeNode pre = null; 5 while (root != null || !stack.isEmpty()) { 6 while (root != null) { 7 stack.push(root); 8 root = root.left; 9 } 10 root = stack.pop(); 11 if(pre != null && root.val <= pre.val) return false; 12 pre = root; 13 root = root.right; 14 } 15 return true; 16 }
注意:不能使用出栈值与栈顶进行比较,因为在中序遍历的过程中栈顶可能为空,所以此时无法比较。