代码随想录刷题day21丨669. 修剪二叉搜索树,108.将有序数组转换为二叉搜索树,538.把二叉搜索树转换为累加树,二叉树总结

news2024/11/13 12:10:00

代码随想录刷题day21丨669. 修剪二叉搜索树,108.将有序数组转换为二叉搜索树,538.把二叉搜索树转换为累加树,二叉树总结

1.题目

1.1修剪二叉搜索树

  • 题目链接:669. 修剪二叉搜索树 - 力扣(LeetCode)

    在这里插入图片描述

  • 视频讲解:你修剪的方式不对,我来给你纠正一下!| LeetCode:669. 修剪二叉搜索树_哔哩哔哩_bilibili

  • 文档讲解:https://programmercarl.com/0669.%E4%BF%AE%E5%89%AA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html

  • 解题思路:递归法

    • 确定递归函数的参数以及返回值

      • 这里我们为什么需要返回值呢?

        因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。

        但是有返回值,更方便,可以通过递归函数的返回值来移除节点。

    • 确定终止条件

      • 修剪的操作并不是在终止条件上进行的,所以就是遇到空节点返回就可以了。
    • 确定单层递归的逻辑

      • 如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。
      • 如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。
      • 接下来要将下一层处理完左子树的结果赋给root->left,处理完右子树的结果赋给root->right。
      • 最后返回root节点
  • 代码:

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode() {}
     *     TreeNode(int val) { this.val = val; }
     *     TreeNode(int val, TreeNode left, TreeNode right) {
     *         this.val = val;
     *         this.left = left;
     *         this.right = right;
     *     }
     * }
     */
    class Solution {
        public TreeNode trimBST(TreeNode root, int low, int high) {
            if(root == null){
                return null;
            }
            if(root.val < low){
                TreeNode right = trimBST(root.right,low,high);
                return right;
            }
            if(root.val > high){
                TreeNode left = trimBST(root.left,low,high);
                return left;
            }
            root.left = trimBST(root.left,low,high);
            root.right = trimBST(root.right,low,high);
            return root;
        }
    }
    
  • 总结:

    • 错误的想法就是:递归处理,然后遇到 root->val < low || root->val > high 的时候直接return NULL

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

  • 题目链接:108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)

    在这里插入图片描述

  • 视频讲解:构造平衡二叉搜索树!| LeetCode:108.将有序数组转换为二叉搜索树_哔哩哔哩_bilibili

  • 文档讲解:https://programmercarl.com/0108.%E5%B0%86%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E8%BD%AC%E6%8D%A2%E4%B8%BA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html

  • 解题思路:递归

    • 从数组中间位置取值作为节点元素
    • 本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间
    • 分割点就是数组中间位置的节点。
    • 如果数组长度为偶数,中间节点有两个,取哪一个?
      • 取哪一个都可以,只不过构成了不同的平衡二叉搜索树。
    • 左下标 left 和右下标 right
    • 这里注意,我这里定义的是左闭右闭区间,在不断分割的过程中,也会坚持左闭右闭的区间,这又涉及到循环不变量
  • 代码:

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode() {}
     *     TreeNode(int val) { this.val = val; }
     *     TreeNode(int val, TreeNode left, TreeNode right) {
     *         this.val = val;
     *         this.left = left;
     *         this.right = right;
     *     }
     * }
     */
    class Solution {
        public TreeNode sortedArrayToBST(int[] nums) {
            TreeNode root = traversal(nums,0,nums.length -1);
            return root;
        }
    
        public TreeNode traversal(int[] nums,int left,int right){
            //左闭右闭
            if(left > right){
                return null;
            }
            int mid = (left + right)/2;
            TreeNode root = new TreeNode(nums[mid]);
            root.left = traversal(nums,left,mid -1);
            root.right = traversal(nums,mid+1,right);
            return root;
        }
    }
    
  • 总结:

    • 在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下标来操作原数组。
    • 迭代法可以通过三个队列来模拟,一个队列放遍历的节点,一个队列放左区间下标,一个队列放右区间下标。

1.3把二叉搜索树转换为累加树

  • 题目链接:538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)

    在这里插入图片描述

  • 视频讲解:普大喜奔!二叉树章节已全部更完啦!| LeetCode:538.把二叉搜索树转换为累加树_哔哩哔哩_bilibili

  • 文档讲解:https://programmercarl.com/0538.%E6%8A%8A%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E8%BD%AC%E6%8D%A2%E4%B8%BA%E7%B4%AF%E5%8A%A0%E6%A0%91.html

  • 解题思路:递归(右中左)+ 双指针

    • 从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了
    • 需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加。
    • 需要定义一个全局变量pre,用来保存cur节点的前一个节点的数值,定义为int型就可以了。
  • 代码:

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode() {}
     *     TreeNode(int val) { this.val = val; }
     *     TreeNode(int val, TreeNode left, TreeNode right) {
     *         this.val = val;
     *         this.left = left;
     *         this.right = right;
     *     }
     * }
     */
    class Solution {
        int pre = 0;
        public TreeNode convertBST(TreeNode root) {
            traversal(root);
            return root;
        }
    
        public void traversal(TreeNode cur){
            if(cur == null){
                return;
            }
            //右
            traversal(cur.right);
            //中
            cur.val += pre;
            pre = cur.val;
            //左
            traversal(cur.left);
        }
    }
    
  • 总结:

    • 注意要右中左来遍历二叉树, 中节点的处理逻辑就是让cur的数值加上前一个节点的数值。

2.二叉树总结

  • 看到递归,就去想:返回值、参数是什么?终止条件是什么?单层逻辑是什么?

  • 递归与迭代究竟谁优谁劣呢?

    • 从时间复杂度上其实迭代法和递归法差不多(在不考虑函数调用开销和函数调用产生的堆栈开销),但是空间复杂度上,递归开销会大一些,因为递归需要系统堆栈存参数返回值等等。

    • 递归更容易让程序员理解,但收敛不好,容易栈溢出。

    • 这么说吧,递归是方便了程序员,难为了机器(各种保存参数,各种进栈出栈)。

    • 在实际项目开发的过程中我们是要尽量避免递归!因为项目代码参数、调用关系都比较复杂,不容易控制递归深度,甚至会栈溢出

    • 一定要掌握前中后序一种迭代的写法,并不因为某种场景的题目一定要用迭代,而是现场面试的时候,面试官看你顺畅的写出了递归,一般会进一步考察能不能写出相应的迭代。

    • 层序遍历遍历相对容易一些,只要掌握基本写法(也就是框架模板),剩下的就是在二叉树每一行遍历的时候做做逻辑修改。

    • 翻转二叉树的递归用中序遍历是不行的,因为使用递归的中序遍历,某些节点的左右孩子会翻转两次。

    • 根节点的高度就是二叉树的最大深度

    • 使用前序(中左右)的遍历顺序,这才是真正求深度的逻辑!

    • 求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。

    • 迭代法中究竟什么时候用队列,什么时候用栈?

      • 如果是模拟前中后序遍历就用栈,如果是适合层序遍历就用队列,当然还是其他情况,那么就是 先用队列试试行不行,不行就用栈
    • 回溯隐藏在traversal(cur->left, path + “->”, result);中的 path + “->”。 每次函数调用完,path依然是没有加上"->" 的,这就是回溯了。

    • 求二叉树的各种最值,就想应该采用什么样的遍历顺序,确定了遍历循序,其实就和数组求最值一样容易了

    • 递归函数究竟什么时候需要返回值,什么时候不要返回值?

      • 一般情况下:如果需要搜索整棵二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径了就要及时返回。
      • 特别是有些时候 递归函数的返回值是bool类型,一些同学会疑惑为啥要加这个,其实就是为了找到一条边立刻返回。
      • 其实还有一种就是后序遍历需要根据左右递归的返回值推出中间节点的状态,这种需要有返回值
    • 构造二叉树有三个注意的点:

      • 分割时候,坚持区间不变量原则,左闭右开,或者左闭右闭。
      • 分割的时候,注意后序 或者 前序已经有一个节点作为中间节点了,不能继续使用了。
      • 如何使用切割后的后序数组来切合中序数组?利用中序数组大小一定是和后序数组的大小相同这一特点来进行切割。
    • 为什么前序和后序不能唯一构成一棵二叉树

      • 因为没有中序遍历就无法确定左右部分,也就无法分割
    • 注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,这样可以节约时间和空间上的开销。

    • 递归函数什么时候加if,什么时候不加if

      • 其实就是控制空节点(空指针)是否进入递归,是不同的代码实现方式,都是可以的。
      • 一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。
    • 如何 一起遍历两棵二叉树?

      • 迭代法中,一般一起操作两个树都是使用队列模拟类似层序遍历,同时处理两个树的节点,这种方式最好理解,如果用模拟递归的思路的话,要复杂一些。
    • 大多二叉搜索树的题目,其实都离不开中序遍历,因为这样就是有序的。

    • 二叉搜索树的特性?

      • 节点的左子树只包含小于当前节点的数。
      • 节点的右子树只包含大于当前节点的数。
      • 所有左子树和右子树自身必须也是二叉搜索树。
    • 我们在验证二叉搜索树的时候,有两个陷阱:

      • 陷阱一

      不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了,而是左子树都小于中间节点,右子树都大于中间节点。

      • 陷阱二

      在一个有序序列求最值的时候,不要定义一个全局变量,然后遍历序列更新全局变量求最值。因为最值可能就是int 或者 longlong的最小值。

      推荐要通过前一个数值(pre)和后一个数值比较(cur),得出最值。

      在二叉树中通过两个前后指针作比较,会经常用到

    • 二叉搜索树和中序遍历是好朋友!

    • 平衡二叉搜索树是不是二叉搜索树和平衡二叉树的结合?

      • 是的,是二叉搜索树和平衡二叉树的结合。
    • 平衡二叉树与完全二叉树的区别在于底层节点的位置?

      • 是的,完全二叉树底层必须是从左到右连续的,且次底层是满的。
    • 堆是完全二叉树和排序的结合,而不是平衡二叉搜索树?

      • 堆是一棵完全二叉树,同时保证父子节点的顺序关系(有序)。 但完全二叉树一定是平衡二叉树,堆的排序是父节点大于子节点,而搜索树是父节点大于左孩子,小于右孩子,所以堆不是平衡二叉搜索树

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2103311.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

bootstrap下拉多选框

1、引用(引用资源下载) <!-- Latest compiled and minified CSS --> <link rel"stylesheet" href"static/css/bootstrap-select.min.css"> <!-- Latest compiled and minified JavaScript --> <script src"static/js/bootstrap…

golang-开发工具及package

1. 开发工具 工欲善其事&#xff0c;必先利其器&#xff0c;我选择vscode&#xff0c;其它的工具比如goland也不错 下载地址&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 我的环境是是debian linux&#xff0c;所以我下载deb包&#xff0c;下载完成后&am…

CTFHub技能树-备份文件下载-vim缓存

目录 方法一&#xff1a;直接浏览器访问 方法二&#xff1a;使用kali恢复vim缓存文件 方法三&#xff1a;直接使用curl访问 最后同样备份文件系列的都可用dirsearch扫描 当开发人员在线上环境中使用 vim 编辑器&#xff0c;在使用过程中会留下 vim 编辑器缓存&#xff0c;当…

江科大/江协科技 STM32学习笔记P30

文章目录 一、FlyMcu串口下载1、串口下载的流程2、串口烧录的选项字节区 二、STLINK Utility 一、FlyMcu串口下载 1、串口下载的流程 例如机器人给自己换电池&#xff0c;需要拆掉旧电池再装上新电池&#xff0c;为了实现这个步骤需要再做一个小机器人&#xff0c;需要换电池时…

WinCC Modbus TCP 通信

概述 从版本WinCC V7.0 开始&#xff0c;WinCC支持Modbus TCP通讯&#xff0c;WinCC中的Modbus TCP驱动主要是针对施耐德PLC开发的&#xff0c;支持的PLC类型如下&#xff1a; 图1 本文档以Quantum CPU651和 Premium P57为例&#xff0c;介绍WinCC V7.2 的Modbus TCP通讯的组…

随手记:小程序体积超出2M包大小如何优化

小程序的包体积限制是2M&#xff0c;超出包大小如何优化 先简单列出&#xff0c;最近比较忙&#xff0c;后续优化明细&#xff0c;有着急的先留言踢我 1.分包 留几个主要的页面体积小的&#xff0c;剩下的在page.json中拆到subpackages中&#xff0c;简单举个例子 "page…

总结一下windows电脑字体模糊的优化方案

问题&#xff1a;谷歌浏览器上页面显示的字体非常细&#xff0c;有点费眼睛了&#x1f47e; 解决方案&#xff1a; 方案1&#xff1a;手动调整ClearType文本。方案2&#xff1a;英伟达显卡控制面板->管理3d设置->关闭全局平滑FXAA&#xff08;如果某个软件需要使用平滑处…

《‌黑神话:‌悟空》‌游戏攻略‌

时光荏苒&#xff0c;岁月如梭&#xff0c;不知不觉已经来到了2024年的9月份了。 ‌突然想写一篇关于《‌黑神话&#xff1a;‌悟空》‌的游戏攻略‌。 在《‌黑神话&#xff1a;‌悟空》‌这款以中国古代名著《‌西游记》‌为背景的动作角色扮演游戏中&#xff0c;‌玩家将扮…

J.U.C Review - 阻塞队列原理/源码分析

文章目录 阻塞队列的由来BlockingQueue的操作方法BlockingQueue的实现类ArrayBlockingQueueLinkedBlockingQueueDelayQueuePriorityBlockingQueueSynchronousQueue 阻塞队列原理深入分析1. 构造器和监视器初始化2. put操作的实现3. take操作的实现4. 注意事项小结 线程池中的阻…

泰克THDP0100(Tektronix)thdp0100高压差分探头详情资料

泰克 THDP0100 高压差分探头具有较大的差分动态范围功能&#xff0c;为用户提供了安全的高压测量探头解决方案。每个探头都配有两种尺寸的钩尖&#xff0c;并具有超范围视觉和声音指示器&#xff0c;当用户超出探头的线性范围时会发出警告。泰克 THDP0100 探头配备 TEkVPI 接口…

【vue css】css字体设置渐变色

实现的效果&#xff1a; 添加的代码&#xff1a; h2 {background-image: -webkit-linear-gradient(bottom, #1bffff, #ffffff);background-clip: text;//背景被裁剪成文字的前景色。-webkit-text-fill-color: transparent;//指定了文本字符的填充颜色。若未设置此属性&#xf…

【Linux操作系统】:Linux生产者消费者模型

目录 生产者消费者模型的概念 生产者消费者模型的特点 生产者消费者模型优点 基于BlockingQueue的生产者消费者模型 基于 BlockingQueue 的生产者消费者模型的概念 模拟实现基于阻塞队列的生产消费模型 生产者消费者模型的概念 生产者消费者模式就是通过一个容器来解决生…

MySQL Email验证流程详解:从注册到激活!

MySQL Email通知系统搭建教程&#xff01;如何从MySQL发送邮件&#xff1f; MySQL Email验证是一个至关重要的环节&#xff0c;它确保了用户注册过程的安全性和有效性。AokSend将详细介绍从用户注册到MySQL Email激活的完整流程&#xff0c;帮助开发者更好地理解和实现这一功能…

东风汽车将出席第五届中国新能源汽车热管理创新国际峰会

2024第五届中国新能源汽车热管理创新国际峰会将于11月14-15日在上海召开。峰会将汇聚来自全球的行业专家、学者、企业领袖及技术精英&#xff0c;共同探讨新能源汽车热管理领域的最新技术成果和发展趋势。 本次峰会将涵盖整车热管理系统构建、新能源商用车热管理、智能热管理系…

Python OpenCV 影像处理:傅立叶转换

►前言 上篇介绍基于计算影像的梯度&#xff0c;通过在影像中找到梯度值的变化来识别边缘。 本篇将介绍傅立叶变换的基本原理&#xff0c;了解傅立叶变换是如何将影像从空间域转换到频率域的&#xff0c;以及为什么这种转换在影像处理过程中是有用的。以及傅立叶变换的实际应…

9.3 k8s介绍

⼀、编排分类 单机容器编排: docker-compose 容器集群编排: docker swarm、mesosmarathon、kubernetes 应⽤编排: ansible(模块&#xff0c;剧本&#xff0c;⻆⾊) ⼆、系统管理进化史 1. 传统部署时代 早期&#xff0c;各个组织是在物理服务器上运⾏应⽤程序。 由于⽆法限…

getLocation:fail, the permission value is offline verifying

getLocation:fail, the permission value is offline verifying 后端会根据appid和secret生成 签名&#xff0c;前端wx配置时一定用appid来验证签名的正确 本次错误为配置初始化失败&#xff1a;前端与后端的appId不一致&#xff0c;我的失误也

TikTok直播为什么要用独立IP

TikTok直播作为一种受欢迎的社交媒体形式&#xff0c;吸引了越来越多的用户和内容创作者。在进行TikTok直播时&#xff0c;选择使用独立IP地址是一种被广泛推荐的做法。本文将探讨为什么在TikTok直播中更推荐使用独立IP&#xff0c;并解释其优势和应用。 独立IP是指一个唯一的互…

探索Linux项目自动化构建:make/Makefile的使用方法

&#x1f331;博客主页&#xff1a;青竹雾色间 &#x1f331;系列专栏&#xff1a;Linux &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞 ⭐收藏 ➕关注 标题&#xff1a; 使用 Makefile 实现项目自动化构建 - 从零开始学习 Makefile 摘要&#xff1a; Makefile 是一个用…

如何在 OpenCloudOS 上安装 OpenTenBase 数据库

OpenTenBase 是由开放原子开源基金会孵化及运营的开源项目&#xff0c;是一款企业级的分布式 HTAP 数据库&#xff0c;具备高扩展性、商业数据库语法兼容、分布式 HTAP 引擎、多级容灾和多维度资源隔离等能力&#xff0c;目前已经成功应用于金融、医疗、航天等诸多行业的核心业…