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

news2025/1/24 18:02:18

文章目录

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

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

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

相关文章

EasyCaptcha,开源图形验证码新标杆!

引言&#xff1a; 随着互联网的普及&#xff0c;验证码已成为网站和应用程序中不可或缺的安全组件。它能够有效地防止自动化攻击、垃圾邮件和机器人活动。在众多验证码解决方案中&#xff0c;Easy-captcha以其简单易用和高度可定制的特点受到了开发者的青睐。本文将指导读者如…

LeetCode:69.x的平方根

嗨嗨嗨&#xff0c;二分又来了&#xff0c;淦它&#xff0c; 这个题官解是&#xff0c;C函数法&#xff0c;二分&#xff0c;和牛顿迭代法&#xff08;暂且搁置&#xff09;&#xff0c; 当然还有暴力&#xff08;不必讨论&#xff0c;就从0开始一个一个试&#xff09;&#…

Ubuntu Desktop - scrolling (Terminal 缓存更多终端历史输出内容)

Ubuntu Desktop - scrolling [Terminal 缓存更多终端历史输出内容] 1. ubuntu-14.04.5-desktop-amd64.iso2. ubuntu-16.04.3-desktop-amd64.isoReferences Terminal -> 右键 Profiles -> Profile Preferences 1. ubuntu-14.04.5-desktop-amd64.iso 2. ubuntu-16.04.3-de…

IM聊天系统为什么需要做消息幂等?如何使用Redis以及Lua脚本做消息幂等【第12期】

0前言 消息收发模型 第一张图是一个时序图&#xff0c;第二张图是一个标清楚步骤的流程图&#xff0c;更加清晰。消息的插入环节主要在2步。save部分。主要也是对这个部分就行消息幂等的操作。 前情提要&#xff1a;使用Redis发布 token 以及lua脚本来共同完成消息的幂等 目…

数据结构(4) 链表(链式存储)

链表&#xff08;链式存储&#xff09; 单链表定义基本操作的实现单链表的插入按位序插入指定节点的前插指定节点的后插 单链表的删除 小结 单链表 定义 顺序表优点:可随机存取&#xff0c;存储密度高&#xff0c;缺点:要求大片连续空间&#xff0c;改变容量不方便。 单链表优…

winprop二次开发

winprop二次开发 前言工具1——整合多个天线结果用途代码实现 工具2——wallman辅助工具 前言 工作需求&#xff0c;对该软件进行简单地二次开发&#xff0c;都是一些挺简单的代码&#xff0c;单纯是为了上传之后将其从本地删除 工具1——整合多个天线结果 用途 winprop最终…

MIT-Missing Semester_Topic 3:Editors (Vim) 练习题

文章目录 练习一练习二练习三练习四练习五练习六练习七练习八 本 Topic 的 MIT 讲解网页&#xff08;练习题未给解答&#xff09; 练习一 自行完成 vimtutor。vimtutor 是 Vim 本身附带的一个入门教程&#xff0c;在 shell 中直接输入 vimtutor 便能运行。注意该教程在 8024 大…

第2讲投票系统后端架构搭建

创建项目时&#xff0c;随机选择一个&#xff0c;后面会生成配置properties文件 生成文件 maven-3.3.3 设置阿里云镜像 <?xml version"1.0" encoding"UTF-8"?><!-- Licensed to the Apache Software Foundation (ASF) under one or more cont…

助力智能化农田作物除草,基于轻量级YOLOv8n开发构建农田作物场景下玉米苗、杂草检测识别分析系统

在我们前面的系列博文中&#xff0c;关于田间作物场景下的作物、杂草检测已经有过相关的开发实践了&#xff0c;结合智能化的设备可以实现只能除草等操作&#xff0c;玉米作物场景下的杂草检测我们则少有涉及&#xff0c;这里本文的主要目的就是想要基于最新的YOLOv8下最轻量级…

【开源】JAVA+Vue.js实现高校学院网站

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学院院系模块2.2 竞赛报名模块2.3 教育教学模块2.4 招生就业模块2.5 实时信息模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 学院院系表3.2.2 竞赛报名表3.2.3 教育教学表3.2.4 招生就业表3.2.5 实时信息表 四、系…

Kafka 入门介绍

目录 一. 前言 二. 使用场景 三. 分布式的流平台 四. Kafka 的基本术语 4.1. 主题和日志 &#xff08;Topic 和 Log&#xff09; 4.2. 分布式&#xff08;Distribution&#xff09; 4.3. 异地数据同步技术&#xff08;Geo-Replication&#xff09; 4.4. 生产者&#xf…

2.2-学成在线内容管理之课程分类查询+新增课程

文章目录 内容管理模块4 课程分类查询4.1 需求分析4.2 接口定义4.3 接口开发4.3.1 树型表查询4.3.2 开发Mapper 4.4 接口测试4.4.1 接口层代码完善4.4.2 测试接口 5 新增课程5.1 需求分析5.1.1 业务流程4.1.2 数据模型 5.2 接口定义5.3 接口开发5.3.1 保存课程基本信息5.3.2 保…

ZigBee学习——BDB

✨本博客参考了善学坊的教程&#xff0c;并总结了在实现过程中遇到的问题。 善学坊官网 文章目录 一、BDB简介二、BDB Commissioning Modes2.1 Network Steering2.2 Network Formation2.3 Finding and Binding&#xff08;F & B&#xff09;2.4 Touchlink 三、BDB Commissi…

【linux系统体验】-ubuntu简易折腾

ubuntu 一、终端美化二、桌面美化2.1 插件安装2.2 主题和图标2.3 美化配置 三、常用命令 以后看不看不重要&#xff0c;咱就是想记点儿东西。一、终端美化 安装oh my posh&#xff0c;参考链接&#xff1a;Linux 终端美化 1、安装字体 oh my posh美化工具可以使用合适的字体&a…

深入浅出CChart 每日一课——红花当然配绿叶,CChart辅助图形绘制

各位同学&#xff0c;好久不见&#xff0c;我可想死你们了&#xff01;&#xff01;&#xff01;咦&#xff0c;那位不是巩叔吗&#xff1f;不好意思&#xff0c;侵权了&#xff0c;请多担待_。 前面的课程呢&#xff0c;拓展的内容比较多&#xff0c;最近笨笨想聚焦在CChart本…

微服务多级缓存

多级缓存 1.什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;如图&#xff1a; 存在下面的问题&#xff1a; •请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈 •Redis缓存…

Structured Streaming

目录 一、概述 &#xff08;一&#xff09;基本概念 &#xff08;二&#xff09;两种处理模型 &#xff08;三&#xff09;Structured Streaming和Spark SQL、Spark Streaming关系 二、编写Structured Streaming程序的基本步骤 &#xff08;一&#xff09;实现步骤 &…

jsp计算机线上教学系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 计算机线上教学系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5…

WebSocketServer方法里注入不了其他类

请直接看原文: WebSocketServer无法注入其他对象的问题 - 知乎 (zhihu.com) WebSocket服务无法使用自动注入解决方法_websocket sever不可以直接注入吧-CSDN博客 ------------------------------------------------------------------------------------------------------…