代码随想录刷题笔记 DAY 23 | 修剪二叉搜索树 No.669 | 将有序数组转换为二叉搜索树 No.108 | 把二叉搜索树转换为累加树 No.538

文章目录

    • Day 23
      • 01. 修剪二叉搜索树(No. 669)
        • 1.1 题目
        • 1.2 笔记
        • 1.3 代码
      • 02. 将有序数组转换为二叉搜索树(No. 108)
        • 2.1 题目
        • 2.2 笔记
        • 2.3 代码
      • 03. 把二叉搜索树转换为累加树(No. 538)
        • 3.1 题目
        • 3.2 笔记
        • 3.3 代码

Day 23

01. 修剪二叉搜索树(No. 669)

题目链接

代码随想录题解

1.1 题目

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

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

示例 1:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:root = [1,0,2], low = 1, high = 2
输出:[1,null,2]

示例 2:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:root = [3,0,4,null,2,null,null,1], low = 1, high = 3
输出:[3,2,null,1]

提示:

  • 树中节点数在范围 [1, 104]
  • 0 <= Node.val <= 104
  • 树中每个节点的值都是 唯一
  • 题目数据保证输入是一棵有效的二叉搜索树
  • 0 <= low <= high <= 104
1.2 笔记

在解这道题之前,先来看一段代码

public TreeNode traversal(root) {
    if (root == null) {
        return null;
    }
    root.left = traversal(root.left);
    root.right = traversal(root.right);
    return root;
}

这段代码实现了什么呢?

根据递归来分析

  • 递归的出口:root == null
  • 递归的返回值,以及其用途:返回的是当前节点经过处理后的值,将其作为上个节点的左子树或者右子树
  • 对每个节点的操作:分别向左递归,返回左子树,向右递归,返回右子树。

最终可以分析得出,上面的代码就是没有做任何的操作,只是将左子树赋给左子树将右子树赋值给右子树。

❓ 很多朋友看到这里可能怀疑我脑子坏掉了,为什么要举这么无意义的例子呢?

💡 其实换个思路去想,将左子树赋值给左子树,相当于没做任何操作,那如果在递归中进行一些操作,使得这个返回值不是左子树,而是左子树的下的节点,那不就完成了节点的删除吗?

那这道题的思路就清晰了一些,对于不处于规定范围内的节点在递归的过程中去改变返回的值,使得其上个节点得到的是修剪后的子树;但对于处于范围内的节点则负责接收修改的左子树和右子树

那这样递归的框架就能很容易的写出来写出来:

public TreeNode traversal(TreeNode root, int low, int high) {
        if (root == null) {
         
        }
        if (root.val > high) {
           
        } else if (root.val < low) {
  
        } else {
            root.right = traversal(root.right, low, high);
            root.left = traversal(root.left, low, high);  
            return root;
        }
    }
  1. 先确定了返回值:送分题,root == null,因为对空节点的任何操作都没有意义。
  2. 然后对该节点不处于规定范围和处于规定范围做不同的处理。
  3. 对于处于规定范围的节点直接负责接收值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后来看这个具体的案例,来思考如果节点处于范围外应该去做些什么:回想一下上面提到的,修剪其实就是让本节点的返回值不再是它自己而是它的符合情况的子树

  • 节点 0 是在范围外的,所以它的右子树可能在范围内,所以这里返回的就是它的向右递归搜索的结果,思考到这里就可以了,递归一定不要去特别深入的思考,否则很容易将自己绕进去

  • 这里理顺这个关系就可以:首先要去返回它符合条件子树来达到修剪的目的,而符合条件的子树肯定是出现在该节点的右子树,然后在右子树中去执行相同的逻辑,那调用这个方法最终返回的结果就是符合规范的子树。

  • 比如 0 节点返回的就是 1 2 这个子树

    return traversal(root.right);
    

那对于 root.val > high 的处理情况也很清晰了,要去它 左子树 去得到符合规范的子树。

return traversal(root.left)k

将上面的代码补充完整。

1.3 代码
class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) {
            return null;
        }
        if (root.val > high) {
            return trimBST(root.left, low, high);
        } else if (root.val < low) {
            return trimBST(root.right, low, high);
        } else {
            root.right = trimBST(root.right, low, high);
            root.left = trimBST(root.left, low, high);  
            return root;
        }
    }
}

02. 将有序数组转换为二叉搜索树(No. 108)

题目链接

代码随想录题解

2.1 题目

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

示例 1:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:

示例 2:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:nums = [1,3]
输出:[3,1]
解释:[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums严格递增 顺序排列
2.2 笔记

延续上一道题,其实构造一个二叉树无非也就是这样的思路:

首先将这个节点创造出来,然后分别向两侧去遍历,使得返回值是构造好的子树,并且将这个子树置于其左子树和右子树即可。

先来写一个基础的结构

public TreeNode traversal(int[] nums, int startIndex, int endIndex) {
	if () {
        // 终止条件
    }
    TreeNode node = new TreeNode(); // 构造新节点的条件
    node.right = traversal(); // 右递归的条件传输
    node.left = traversal(); // 左递归的条件传输
    return node;
}

💡 这里涉及到了逻辑切割数组,可以查看一下我这篇博客的第三道题目

  • 代码随想录刷题笔记 DAY 18 | 找树左下角的值 No.513 | 路经总和 No.112 | 从中序与后序遍历序列构造二叉树 No.106
  • 其实理解起来也很容易,就是传入数组的起始和终止位置来约束来达到和分割数组相同的效果。

接下来就是依照题目去一点点解决这些问题了:

👉 构造节点的条件

  • 这里才开始做和这道题目有关的事情,首先题目交给的就已经是排序好的数组,只需要保证左右子树平衡即可,也就是考虑怎样分割数组的问题。

    • 平衡就需要保证左子树和右子树的节点数量尽量相同,那 分割点起始就是数组中间点

    • 将代码补充出来:

      int mid = (startIndex + endIndex) / 2;
      Treenode node = new TreeNode(nums[mid]);
      

👉 左右递归的条件传输

  • 那分析到这里其实做有递归的条件也很容易写出来了,就是从 startIndexmid - 1 作为其左子树, mid + 1endIndex 作为其右子树。

    • 将代码补充出来

      node.left = traversal(nums, startIndex, mid - 1);
      node.right = traversal(nums, mid + 1, endIndex);
      

👉 递归的终点

  • 当是实际的切割数组的时候,终止条件其实很容易写出,就是 nums == null 的时候,但是对于这种逻辑切割就要考虑一下了。

  • 答案是 startIndex > endIndex 而不是 startIndex == endIndex,因为在过程中如果出现表示的数组为空,逻辑的起始和终止就会出现这种情况,可以当作结论记忆。

    • 将代码补充出来

      if (startIndex > endIndex) {
      	return null;
      }
      
2.3 代码
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return traversal(nums, 0, (nums.length - 1));
    }
    public TreeNode traversal(int[] nums, int startIndex, int endIndex) {
        if (startIndex > endIndex) {
            return null;
        }
        int mid = (startIndex + endIndex) / 2;
        TreeNode node = new TreeNode(nums[mid]);
        node.left = traversal(nums, startIndex, mid - 1);
        node.right = traversal(nums, mid + 1, endIndex);
        return node;
    }
}

03. 把二叉搜索树转换为累加树(No. 538)

题目链接

代码随想录题解

3.1 题目

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

  • 节点的左子树仅包含键 小于 节点键的节点。
  • 节点的右子树仅包含键 大于 节点键的节点。
  • 左右子树也必须是二叉搜索树。

**注意:**本题和 1038: https://leetcode-cn.com/problems/binary-search-tree-to-greater-sum-tree/ 相同

示例 1:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

示例 2:

输入:root = [0,null,1]
输出:[1,null,1]

示例 3:

输入:root = [1,0,2]
输出:[3,3,2]

示例 4:

输入:root = [3,2,4,1]
输出:[7,9,4,10]

提示:

  • 树中的节点数介于 0104 之间。
  • 每个节点的值介于 -104104 之间。
  • 树中的所有值 互不相同
  • 给定的树为二叉搜索树。
3.2 笔记

题目中给出的是二叉搜索树,来观察上面的 示例 1

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

累加树的特征为:每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

二叉搜索树的最右边的节点是整个树中最大的节点,也就是说大于等于它的节点就是它本身,而再往上推到上图中的节点 7 作为次大的节点,这个节点的值就是它本身加上比他大的值也就是 8,按照这个规律很容易就能得出其他的节点的值,节点 6 的值就是 6 + 7 + 8 ,而节点 5 的值就是 5 + 6 + 7 + 8

所以这道题的思路就很明确了:以 右、中、左 的顺序去遍历二叉树,在这途中给节点加上路径中的节点和即可。

最后只需要解决如何按照 右、中、左 的顺序去遍历二叉树就可以了,这其实就是一种另类的中序遍历:

traversal(node.left);
System.out.println(node.val);
traversal(node.right);

这样的遍历顺序是 左、中、右,那修改一下

traversal(node.right);
System.out.println(node.val);
traversal(node.left);

这样就能得到符合上面遍历顺序的值。

只要将输出语句改为对节点的操作就能达到倒序的操作树(将搜索树看作升序数组)。

定义一个全局变量为 0,随着遍历逐步累加为 8 15 21 26 然后将其赋值给该节点即可。

  • globalNum += node.val;
    node.val = globalNum;
    
3.3 代码
class Solution {
    int globalNum = 0;
    public TreeNode convertBST(TreeNode root) {
        traversal(root);
        return root;
    }
    public void traversal(TreeNode node) {
        if (node == null) {
            return;
        }
        traversal(node.right);
        globalNum += node.val;
        node.val = globalNum;
        traversal(node.left);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux_进程地址空间

我们用c语言写的程序&#xff0c;经过编译后形成可执行程序存放在硬盘。当运行该程序时&#xff0c;操作系统将该程序加载到内存中&#xff0c;创建进程控制块&#xff0c;变为进程&#xff0c;然后开始执行该程序。大家是否想过&#xff0c;操作系统是如何加载的呢&#xff1b…

有状态DHCPv6快速模式配置及EUI-64介绍

正文共&#xff1a;1024 字 15 图&#xff0c;预估阅读时间&#xff1a;3 分钟 我们现在已经熟悉了IPv6的地址架构&#xff08;IPv6地址架构一本通&#xff09;&#xff0c;掌握了IPv6地址的手工配置方式&#xff08;IPv6从入门到精通&#xff09;和DHCPv6有状态地址配置&#…

01.数据结构篇-链表

1.找出两个链表的交点 160. Intersection of Two Linked Lists (Easy) Leetcode / 力扣 例如以下示例中 A 和 B 两个链表相交于 c1&#xff1a; A: a1 → a2↘c1 → c2 → c3↗ B: b1 → b2 → b3 但是不会出现以下相交的情况&#xff0c;因为每个节点只有一个…

Peter算法小课堂—区间模型(2)

上次咋们讲了前两个区间模型&#xff1a;1.最大不重叠区间数 2.不重叠区间最少分组数。今天我们就学习&#xff1a;最小区间覆盖问题、区间重叠最厚层数&#xff01; 最小区间覆盖 先看三道题 那么&#xff0c;第1题&#xff0c;它是浮点数的题&#xff0c;也就要求首尾相同。…

通过增加缓存优化斐波那契递归的冗余计算

一、python 斐波那契数列的递归实现存在大量的冗余计算。例如&#xff0c;为了计算fib(n)&#xff0c;我们需要计算fib(n-1)和fib(n-2)&#xff0c;但是在计算fib(n-1)的过程中&#xff0c;我们又会重复计算fib(n-2)。当n的值很大时&#xff0c;这种冗余计算会消耗大量的计算资…

机器学习:ROC曲线笔记

ROC曲线&#xff08;Receiver Operating Characteristic Curve&#xff09;是一种用于评估二分类模型性能的图形化工具&#xff0c;主要用于展示在不同阈值&#xff08;Threshold&#xff09;下模型的真阳性率&#xff08;True Positive Rate&#xff0c;TPR&#xff09;和假阳…

最新在线看4K高清电影网站推荐

随着互联网技术的发展&#xff0c;观看高清电影已经不再是难事。这里我为大家分享几个最新的在线看4K高清电影网站&#xff0c;让您在家就能享受到极致观影体验。 通过下面这个即可 1. 【超清影视】 【超清影视】是国内新兴的4K高清电影网站&#xff0c;拥有海量的影片资源&a…

【送书福利-第三十一期】《区块链安全理论与实践(安全技术经典译丛)》

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;程序员洲洲。 &#x1f388; 本文专栏&#xff1a;本文…

幻兽帕鲁游戏官方更新了版本,联机时提示版本不适用,无法加入,怎么办?

如果你在登录游戏的时候提示&#xff1a;您正在尝试加入的比赛正在运行不兼容的游戏版本。请尝试升级游戏版本。此时就说明你需要更新部署在服务器内的幻兽帕鲁了。 1、如果你使用幻兽帕鲁应用模板部署游戏&#xff0c;那么可以选择使用游戏配置面板一键更新。 2、如果你使用一…

使用Xcode 真机无线调试

1.iPhone和Xcode连在同一WIFI下 2.打开Xcode 顶部菜单 选中Window -> Device and Simulators 3.选中Connect via network (注意&#xff1a;勾选前还要用数据线连接,测试机要设置密码,出弹窗的话要点击信任) 真机设备旁边出现小地球 就代表成功了

【ES】--ES集成热更新自定义词库(字典)

目录 一、问题描述二、具体实施1、Tomcat实现远程扩展字典2、验证生效3、ES配置远程扩展字典4、为何不重启ES能实现热更新 一、问题描述 问题现象: 前面完成了自定义分词器词库集成到ES中。在实际项目中词库是时刻在变更的&#xff0c;但又不希望重启ES&#xff0c;对此我们应…

书生·浦语大模型第四课作业

基础作业&#xff1a; 构建数据集&#xff0c;使用 XTuner 微调 InternLM-Chat-7B 模型, 让模型学习到它是你的智能小助手&#xff0c;效果如下图所示&#xff0c;本作业训练出来的模型的输出需要将不要葱姜蒜大佬替换成自己名字或昵称&#xff01; 1.安装 # 如果你是在 Int…

备战蓝桥杯---组合数学基础1

让我们来几道高中的组合题吧&#xff1a; 1.我们一定有n个向下&#xff0c;为 2.我们挑最大的两个&#xff0c;条件是他们奇偶性相同&#xff0c;为2*A10,2; 3.用捆绑法即可。 4.我们用隔板法&#xff0c;为 5.问题等价于23个相同的球放到3个盒子里&#xff0c;每个盒子至少…

如何使用ProcessStomping在可执行程序的字段部分执行Shellcode

关于ProcessStomping ProcessStomping是一款功能强大的Shellcode代码执行工具&#xff0c;该工具允许广大研究人员在目标可执行程序的指定字段部分执行Shellcode代码。 ProcessStomping实际上是Process Overwriting项目的一个升级版本&#xff0c;并且能够向目标应用程序的指…

2000-2021年县域指标统计数据库

2000-2021年县域统计数据库 1、时间&#xff1a;2000-2021年 2、来源&#xff1a;县域统计年鉴 3、范围&#xff1a;2500县 5、指标&#xff1a; 地区名称、年份、行政区域代码、所属城市、所属省份、行政区域土地面积平方公里、乡及镇个数个、乡个数个、镇个数个、街道办…

【Java程序设计】【C00253】基于Springboot的在线考试管理系统(有论文)

基于Springboot的在线考试管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的在线考试系统 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块&#xff1a;系统登录&#xff0c;管理…

二层交换机配置以太网通道

实验大纲 二层聚合端口配置 1.构建网络拓扑结构图 2.修改交换机名字 3.创建聚合组进入聚合接口模式 4.将端口绑定到聚合端口&#xff08;接口模式&#xff09; 5.聚合接口下端口配置&#xff08;聚合接口模式) 6.具体配置 7.验证端口通道1的状态 8.配置ip 9.测试连通…

Learn LaTeX 017 - LaTex Multicolumn 分栏

在科学排版中进行分栏操作&#xff0c;能够有效的利用页面中的空间&#xff0c;避免空白位置的浪费。 好的分栏设计能对你的排版增色不少&#xff01; https://www.ixigua.com/7298100920137548288?id7307237715659981346&logTag949adb699806392430bb

centos中docker操作+安装配置django并使用simpleui美化管理后台

一、安装docker 确保系统是CentOS 7并且内核版本高于3.10,可以通过uname -r命令查看内核版本。 更新系统软件包到最新版本,可以使用命令yum update -y。 安装必要的软件包,包括yum-utils、device-mapper-persistent-data和lvm2。使用命令yum install -y yum-utils devic…

Android的常用Drawable讲解

今天来讲讲Android开发中水都绕不开的东西----drawable。最常使用的莫过于通过XML所声明的Drawable作为View背景&#xff0c;通过代码创建的应用场景则较少。其有着使用简单&#xff0c;比自定义view的成本要低的特点。同时&#xff0c;非图片类型的drawable占用空间较小&#…