二叉搜索树变成二叉平衡树
二叉搜索树:
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
二叉平衡搜索树:
具有搜索树的特点的基础上,同时左右节点的树的高度差不大于1.
在这里插入代码片
class Solution {
ArrayList<Integer> list=new ArrayList<>();
public void travel(TreeNode cur){
if(cur==null){
return;
}
travel(cur.left);
list.add(cur.val);
travel(cur.right);
}
public TreeNode getNode(List<Integer> num, int left, int right){
if(left>right){
return null;
}
if(left==right){
return new TreeNode(num.get(left));
}
int mid=left+(right-left)/2; //先得到的是中间的节点
TreeNode root=new TreeNode(num.get(mid));
root.left=getNode(num,left,mid-1); //根节点的左节点是二分法之后的中间节点
root.right=getNode(num,mid+1,right);
return root;
}
public TreeNode balanceBST(TreeNode root) {
travel(root);
return getNode(list,0,list.size() - 1);
}
}
思路
在这里的话,首先通过中序遍历,得到的是有序的链表,再通过二分法对root节点的左右节点进行创建新的节点。
直到左节点大于右节点的时候,终止。
二叉树的本质就是找到一个根节点,然后按照左右节点进行遍历,遍历的方式可以使用前中后遍历,
不过我一般喜欢使用前序遍历,前序遍历就是先打印出当前的节点的值,再进行左节点的打印,然后是右节点的打印,每一次左节点
打印后会回溯。
给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
例如,
标题二叉搜索树中的搜索
在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。
本题当然可以前序遍历直接遍历完成,但是还是要利用一下搜素二叉树的性质:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉搜索树
答案就呼之欲出了,就是当节点的值大于当前的值的时候寻找左节点,否则寻找右节点,然后终止条件是找到了节点或者说节点的值为空。
在这里插入代码片
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
//注意给的是二叉搜索树,左边比节点小,右边大
if(root==null||root.val==val){
return root;//搜索结束
}
if(root.val>val){
return searchBST(root.left,val);
}else{
return searchBST(root.right,val);
}
}
}
二叉搜索树的最小绝对差
这道题的关键就是变成中序遍历,然后更新最小的值
中序遍历如图所示
首先执行的是 dfs(root.left);
,回溯的终止条件是 if(root==null){ return; }
,然后进行中间值的打印,或者说更新当前的节点的值,此时进行回溯到当前点的值,进行比较更新:
if(pre!=null){
minLen=Math.min(minLen, Math.abs(pre.val-root.val));
}
同时更新前一个点的值
在这里插入代码片
pre=root; //永远记录前一个的节点,中序遍历,此时应该是记录中间的节点
然后进行右节点的遍历。
总体的代码为:
在这里插入代码片
int minLen=Integer.MAX_VALUE;
TreeNode pre;
public int getMinimumDifference(TreeNode root) {
if(root==null){
return 0;
}
dfs(root);
return minLen;
}
public void dfs(TreeNode root){
if(root==null){
return;
}
dfs(root.left);
if(pre!=null){
minLen=Math.min(minLen, Math.abs(pre.val-root.val));
}
pre=root; //永远记录前一个的节点,中序遍历,此时应该是记录中间的节点
dfs(root.right);
}
二叉树的最近公共祖先
我认为这道题是最好的二叉树题目,和那些递归,然后回溯的题目不同,这道题更能体现递归是如何进行回溯的
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//显然是使用递归进行的求解,求解的方法是,求节点的左子树和右子树看看是否为null
if(root==null ||root==p || root==q){
return root;//终止条件
}
TreeNode left=lowestCommonAncestor(root.left,p,q); //递归的时候的左节点
TreeNode right=lowestCommonAncestor(root.right,p,q); //递归的时候的右子树
//递归的时候的结果
if(left==null &&right==null){
return null;
}
if(left==null){
return right;
}
if(right==null){
return left;
}
return root;
}
}
这道题中终止条件显然是root==p || root==q
,如果left 和 right都不为空,说明此时root就是最近公共节点,这也就是最后直接返回了root的原因
。如果left为空,right不为空,就返回right,说明目标节点是通过right返回的。