目录
轻松解决搜索树难题
二叉搜索树简单来说就是一棵二叉树按照中序遍历其序列正好是一个递增序列,比较规范的定义:
⚪ 若左子树不空,则左子树上所有节点值均小于它的根节点;
⚪ 若右子树不空,则右子树上所有节点值均大于它的根节点;
⚪ 它的左右子树也分别都是二叉搜索树。
一、二叉搜索树中搜索特定值
给定二叉搜索树(BST)的根节点和一个值,在BST中找到节点值等于给定值的节点。返回以该节点为根的子树。如果节点不存在,则返回null。如下所例:
target: 2
输入: 4 输出: 2
/ \ / \
2 6 1 5
/ \
1 5
根据二叉搜索树的有序特征我们可以很容易实现特定值的查找,只需设定如下递归:
⚪ 如果根节点为空或者根节点值等于搜索值,说明不存在(null)或已找到,返回根节点
⚪ 如果搜索值小于根节点的值,说明搜索值在根节点的左子树,这时候只需递归查找该根节点的左子树
⚪ 如果搜索值大于根节点的值,说明搜索值在根节点的右子树,这时候只需递归查找该根节点的右子树
所以上面看起来是不是就很想二分查找,因为和二分查找有序数组其实本质上是一样的,可以说就是二分查找。实现代码如下:
public TreeNode searchBST(TreeNode root, int val) {
// 递归二分查找
if(root == null || root.val == val) return root;
return val < root.val ? searchBST(root.left, val) : searchBST(root.right, val);
}
能用递归实现啦,自然也能用迭代来实现啦,只是把递归换成循环来实现而已,思路一致,实现代码如下:
public TreeNode searchBST(TreeNode root, int val) {
// 迭代二分查找
while(root != null && root.val != val){
root = val < root.val ? root.left : root.right;
}
return root;
}
二、验证二叉搜索树
给你一个二叉树的根节点root,判断其是否是一个有效的二叉树,其实就是让你判断该二叉树中序遍历的序列是否是有序递增的。这道题也是很多二叉搜索树拓展题的基础,所以一定要好好理解这道题,把握其解题思路和清楚变量的设定。
作为基础,这道题的思路自然不会很复杂,只需通过递归的方式,在中序遍历的时候实时检查当前节点是否大于前一个节点的值即可,记住一定要实时更新前一个结点的值! 实现代码如下:
class Solution {
// 记录前一个结点值
long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
// 如果左子树不满足下面判断的要求,返回false
if(!isValidBST(root.left)) return false;
// 子树的节点必须满足:节点值小于中序遍历前一个节点的值
if(root.val <= pre) return false;
// 更新中序遍历前一个节点值为当前节点值
pre = root.val;
// 递归检验右子树
return isValidBST(root.right);
}
}
三、二叉搜索树的最小绝对差
上一道题解决了,在此基础上,我们就可以来挑战二叉搜索树的拓展题啦。做这种题无论描述多复杂,不要慌,本质上都是让你中序遍历,根据其有序性的特征其解决问题的要求。那让我们一起来看看这道题吧,之后的题也就如此思路解决就好啦!
给定一个二叉搜索树的根节点root,返回树中任意两不同节点值之间的最小差值。
任意两节点哦!可能看起来顿时感到害怕,毕竟碰到任意就头大,但先别慌,我说了,要充分利用二叉搜索树的特征,就是他是有序的,所以一个结点和其他结点值的绝对差最小时,该结点只能为其左或右的相邻节点,所以不还是很前面的题一样嘛。在中序遍历的途中,不断更新最小绝对差就好了,所以思路其实一模一样,代码做如下一点改变就好啦!
class Solution {
int min = Integer.MAX_VALUE; // 存放最小绝对差
int pre = -1; // 存放前一个结点的值
public int getMinimumDifference(TreeNode root) {
if(root == null) return -1;
// 递归遍历左结点
getMinimumDifference(root.left);
// 如果为最小的结点,赋予pre初始值为最小节点的值
if(pre == -1) pre = root.val;
else{
// 更新最小绝对差
min = Math.min(min, root.val - pre);
pre = root.val; // 前一个结点更新为当下根结点
}
// 左枝判断玩则遍历到其右节点
getMinimumDifference(root.right);
return min;
}
}