代码随想录算法训练营第23天(二叉树9 | ● 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树 ● 总结篇

二叉树9

  • 669. 修剪二叉搜索树
    • 解题思路
  • 108.将有序数组转换为二叉搜索树
    • 解题思路
  • 538.把二叉搜索树转换为累加树
    • 解题思路
  • 总结篇

669. 修剪二叉搜索树

这道题目比较难,比 添加增加和删除节点难的多,建议先看视频理解。
题目链接/文章讲解: 669. 修剪二叉搜索树
视频讲解:669. 修剪二叉搜索树

解题思路

直接想法就是:递归处理,然后遇到 root.val < low || root.val > high 的时候直接return NULL
但是存在 要删除节点的孩子可能并不需要删除 的情况
递归三部曲:

  1. 确定递归函数的参数以及返回值
    因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。但是有返回值,更方便,可以通过递归函数的返回值来移除节点。
  2. 确定终止条件
    修剪的操作并不是在终止条件上进行的,所以就是遇到空节点返回就可以了
  3. 单层递归逻辑
    如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。
    如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。
    接下来要将下一层处理完左子树的结果赋给root->left,处理完右子树的结果赋给root.right。
class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        // 终止条件
        if(root == null) return root;
        // 中
        if(root.val < low) return trimBST(root.right, low, high); 
        if(root.val > high) return trimBST(root.left, low, high);
        // 左
        root.left = trimBST(root.left, low, high);
        // 右
        root.right = trimBST(root.right, low, high);

        return root;
    }
}

108.将有序数组转换为二叉搜索树

本题就简单一些,可以尝试先自己做做。
题目链接/文章讲解:题目链接/文章讲解:
视频讲解:108.将有序数组转换为二叉搜索树

解题思路

在二叉树:构造二叉树登场!和二叉树:构造一棵最大的二叉树 中其实已经讲过了,如何根据数组构造一棵二叉树。
本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间。 分割点就是数组中间位置的节点。
在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下标来操作原数组。要注意区间划分规则要一致(我们这里是左闭右闭)

  1. 递归终止条件:区间 left > right
  2. 单层递归逻辑:
  • 首先取数组中间元素的位置,不难写出int mid = (left + right) / 2;,这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在二分法中尤其需要注意!,所以可以这么写:int mid = left + ((right - left) / 2); 但本题leetcode的测试数据并不会越界,所以怎么写都可以。但需要有这个意识!
  • 取了中间位置,就开始以中间位置的元素构造节点,代码:TreeNode root = new TreeNode(nums[mid])。
  • 接着划分区间,root的左孩子接住下一层左区间的构造节点,右孩子接住下一层右区间构造的节点。
    最后返回root节点
// 递归  中序遍历
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        if(nums.length == 0) return null;
        return travel(nums, 0, nums.length - 1);
    }
    public TreeNode travel(int[] nums, int left, int right){
        if(left > right) return null;
        int mid = left + ((right - left) >> 1); // 保险起见 统一这样写吧
        TreeNode root = new TreeNode(nums[mid]);
        root.left = travel(nums, left, mid - 1);
        root.right = travel(nums, mid + 1, right);
        return root;
    }
}

538.把二叉搜索树转换为累加树

本题也不难,在 求二叉搜索树的最小绝对差 和 众数 那两道题目 都讲过了 双指针法,思路是一样的。
题目链接/文章讲解:538.把二叉搜索树转换为累加树
视频讲解:538.把二叉搜索树转换为累加树

解题思路

  1. 首先确定遍历顺序:右中左(其实这就是一棵树,大家可能看起来有点别扭,换一个角度来看,这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13]。从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了。
  2. 确定如何保存并累加前一个节点的数值:双指针。(复习:pre指针的使用技巧,二叉树:搜索树的最小绝对差和二叉树:我的众数是多少?
  3. 返回值:不需要
  4. 中节点处理逻辑:让cur的数值加上前一个节点的数值
// 递归 右中左
class Solution {
    int pre = 0; // 注意:pre一定得设为全局变量
    public TreeNode convertBST(TreeNode root) {
        addTree(root);
        return root;
    }
    public void addTree(TreeNode root){
        if(root == null) return;
        addTree(root.right);  // 右
        root.val = root.val + pre; // 中
        pre = root.val;
        addTree(root.left);   // 左 
    }
}

总结篇

好了,二叉树大家就这样刷完了,做一个总结吧

你可能感兴趣的:(算法,数据结构,java,leetcode)