1、二叉树的最近公共祖先
2、二叉搜索树的最近公共祖先
3、删除二叉搜索树中的节点
4、修剪二叉搜索树
5、将有序数组转换为二叉搜索树
6、有序链表转换二叉搜索树
7、把二叉搜索树转换为累加树
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
题解:
链接: link
求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。
在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null) return root;
if(root==p || root==q) return root;
TreeNode leftNode = lowestCommonAncestor(root.left,p,q);
TreeNode rightNode = lowestCommonAncestor(root.right,p,q);
if(leftNode!=null && rightNode!=null) return root;
if(leftNode==null && rightNode!=null) return rightNode;
else{
return leftNode;
}
}
}
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
当前遍历的结点如果比p和q的数值都大的话,说明公共祖先一定在当前遍历结点的左子树里
当前遍历的结点如果比p和q的数值都小的话,说明公共祖先一定在当前遍历结点的右子树里
当前遍历的结点数值在p和q之间,那么当前遍历的结点就是p和q的公共结点
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null) return null;
TreeNode leftNode ;
TreeNode rightNode ;
if(root.val>p.val && root.val>q.val){
return lowestCommonAncestor(root.left,p,q); //左子树
}
if(root.val<p.val && root.val<q.val){
return lowestCommonAncestor(root.right,p,q); //右子树
}
return root;
}
}
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
有以下五种情况:
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root==null) return root;
root = delete(root,key);
return root;
}
public TreeNode delete(TreeNode root,int key){
if(root==null) return null;
if(root.val>key){
root.left = delete(root.left,key);
}else if(root.val<key){
root.right = delete(root.right,key);
}else{
//相等的情况
if(root.left==null ) return root.right;
if(root.right==null) return root.left;
TreeNode tmpNode = root.right;
while(tmpNode.left!=null){
tmpNode = tmpNode.left;
}
root.val = tmpNode.val;
root.right = delete(root.right,tmpNode.val);
}
return root;
}
}
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
直接想法就是:递归处理,然后遇到 root->val < low || root->val > high 的时候直接return NULL,一波修改,干净利落。
public TreeNode delete(TreeNode root,int low,int high){
if(root ==null) return null;
root.left = delete(root.left,low,high);
root.right = delete(root.right,low,high);
if(root.val<low){
return null;
}
if(root.val>high){
return null;
}
return root;
}
然而[1, 3]区间在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的,还要考虑节点0的右子树。
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null) return null;
return delete(root,low,high);
}
public TreeNode delete(TreeNode root,int low,int high){
if(root ==null) return null;
root.left = delete(root.left,low,high);
root.right = delete(root.right,low,high);
if(root.val<low){
TreeNode rightNode = delete(root.right,low,high);
return rightNode;
}
if(root.val>high){
TreeNode leftNode = delete(root.left,low,high);
return leftNode;
}
return root;
}
}
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
两种方式:
方式一:
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
if(nums.length==0) return null;
int rootIndex = nums.length/2;
TreeNode root = new TreeNode(nums[rootIndex]);
int[] leftNums = new int[rootIndex];
for(int i=0;i<rootIndex;i++){
leftNums[i] = nums[i];
}
int[] rightNums = new int[nums.length-rootIndex-1];
int j=0;
for(int i=rootIndex+1;i<nums.length;i++){
rightNums[j++] = nums[i];
}
root.left = sortedArrayToBST(leftNums);
root.right = sortedArrayToBST(rightNums);
return root;
}
}
方式二:
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
//左闭右开
return buildTree(nums,0,nums.length);
}
public TreeNode buildTree(int[] nums,int begin,int end){
if(begin>end-1) return null;
int rootIndex = (begin+end)/2;
TreeNode root = new TreeNode(nums[rootIndex]);
root.left = buildTree(nums,begin,rootIndex);
root.right = buildTree(nums,rootIndex+1,end);
return root;
}
}
给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。
思路:
重点在于快慢指针找链表中点
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if(head==null) return null;
else if(head.next==null){
return new TreeNode(head.val);
}
//找链表的中点
ListNode pre = head;
ListNode p=pre.next;
ListNode q=p.next;
while(q!=null && q.next!=null){
pre = p;
p = pre.next;
q = q.next.next;
}
//此时p是中点位置
TreeNode root = new TreeNode(p.val);
pre.next=null;
root.left = sortedListToBST(head);
root.right = sortedListToBST(p.next);
return root;
}
}
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
题目解读:
就是求树中大于等于该节点值的所有节点的总和。 如题,最后一个节点是8,那么树中最大的值是8,所以累加和是8;倒数第二个是7,树中全部大于等于7的,只有7和8,所以累加和是15,以此类推…
思路:
想象为有序数组 2,5,6
累加数组: 13,11,6
因此采用倒中序+双指针的遍历方式
class Solution {
TreeNode pre=null;
int newVal =0;
public TreeNode convertBST(TreeNode root) {
if(root == null) return null;
root.right=convertBST(root.right);
//倒中序
TreeNode cur = root;
if(pre!=null){
int newVal = pre.val+cur.val;
root.val = newVal;
}
pre = root;
root.left=convertBST(root.left);
return root;
}
}