day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树

文章目录

  • 前言
  • 一、二叉树的最近公共祖先(力扣236)
  • 二、二叉搜索树的最近公共祖先(力扣235)
  • 三、删除二叉搜索树中的节点(力扣350)
  • 四、修剪二叉搜索树(力扣669)
  • 五、将有序数组转换为二叉搜索树(力扣108)
  • 六、有序链表转换二叉搜索树(力扣109)
  • 七、把二叉搜索树转换为累加树(力扣538)


前言

1、二叉树的最近公共祖先
2、二叉搜索树的最近公共祖先
3、删除二叉搜索树中的节点
4、修剪二叉搜索树
5、将有序数组转换为二叉搜索树
6、有序链表转换二叉搜索树
7、把二叉搜索树转换为累加树


一、二叉树的最近公共祖先(力扣236)

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第1张图片
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第2张图片
题解:
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第3张图片
链接: 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;
        }
    }
}

在这里插入图片描述

二、二叉搜索树的最近公共祖先(力扣235)

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第4张图片
当前遍历的结点如果比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;
    }
}

在这里插入图片描述

三、删除二叉搜索树中的节点(力扣350)

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第5张图片
有以下五种情况:

  • 第一种情况:没找到删除的节点,遍历到空节点直接返回了
  • 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
  • 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
  • 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
  • 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
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;
    }
}

在这里插入图片描述

四、修剪二叉搜索树(力扣669)

给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第6张图片

直接想法就是:递归处理,然后遇到 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的右子树。
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第7张图片

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;
    }
}

在这里插入图片描述

五、将有序数组转换为二叉搜索树(力扣108)

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第8张图片
两种方式:
方式一:

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;
    }
}

在这里插入图片描述

六、有序链表转换二叉搜索树(力扣109)

给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第9张图片
思路:
重点在于快慢指针找链表中点

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;

    }
}

在这里插入图片描述

七、把二叉搜索树转换为累加树(力扣538)

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
day27【代码随想录】、二叉树的最近公共祖先、二叉搜索树的最近公共祖先、删除二叉搜索树中的节点、修剪二叉搜索树、将有序数组转换为二叉搜索树、有序链表转换二叉搜索树、把二叉搜索树转换为累加树_第10张图片
题目解读:

就是求树中大于等于该节点值的所有节点的总和。 如题,最后一个节点是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;
    }
}

在这里插入图片描述


你可能感兴趣的:(代码随想录,算法,数据结构,leetcode,java,链表)