合法二叉搜索树
前言
对于树的处理,遍历是基本功。对于二叉搜索树的合法性,用中序遍历定义中前驱和后继来判断即可。
一、合法二叉搜索树
二、两种解法–两种理解
package everyday;
// 合法二叉搜索树。
public class IsValidBST {
/*
target:判断二叉树是否为二叉搜索树。
二叉搜索树定义,左 < 中 < 右。
1-由于这个小于关系,为二叉树的中序遍历,所以可记录中序遍历下的前驱节点pre,然后比较root和pre的大小关系。
*/
public boolean isValidBST(TreeNode root) {
// 该条路径到达null节点,结束递归。
if (null == root) return true;
// 判断左子树是否满足条件。
boolean flag = isValidBST(root.left);
// 左子树不满足条件,则该树也不是二叉搜索树。
if (!flag) return false;
// 左子树满足条件,用左子树的最右节点pre和root相比,看是否满足条件。
// 不满足条件,该树也不是二叉搜索树。
if (pre >= root.val) return false;
// 满足条件,把前驱替换,继续判断右子树是否满足。
pre = root.val;
// 右边满足了,加上刚才的左边,那么整棵树都满足二叉搜索树条件;右边不满足,那么则整棵树不为二叉搜索树。
return isValidBST(root.right);
}
// bug1:1 << 63 = Integer.MIN_VALUE,因为1默认int。
// private long pre = 1 << 63;
private long pre = 1l << 63;
// Definition for a binary tree node.
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
}
// 能否不用全局变量pre,利用回溯来返回前驱(针对root的前驱) + 传入前驱(针对右子树最左孩子)。
class IsValidBST2 {
/*
target:判断二叉树是否为二叉搜索树。
二叉搜索树定义,左 < 中 < 右。
每次返回一个中序遍历的前驱节点和root比较即可。
root的前驱就是其左子树的最右孩子;右子树最左孩子的前驱就是root。
*/
public boolean isValidBST(TreeNode root) {
inOrder(root, null);
return flag;
}
private TreeNode inOrder(TreeNode root, TreeNode pre) {
// 递归到叶子节点的子节点,终止递归。
if (null == root) return null;
// 当有子树已经不满足二叉搜索树了,直接剪枝。
if (!flag) return null;
// 先左递归
TreeNode left = inOrder(root.left, pre);
// 左子树不为空,要和左子树最右节点比;否则和pre比。
// 砍掉右子树。
if (left != null && left.val >= root.val || left == null && pre != null && pre.val >= root.val) {
System.out.println(left.val);
flag = false;
return null;
}
TreeNode right = inOrder(root.right, root);
// 叶子节点 || 有左无右,都返回root即可。
if (right == null) return root;
// 有左有右 || 无左有右,都返回最右节点即可。
return right;
}
private boolean flag = true;
// Definition for a binary tree node.
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
}
总结
1)处理好任意一颗子树,就处理好了整颗树,这是二叉递归结构的魅力。
参考文献
[1] LeetCode 合法二叉搜索树