代码随想录训练营 Day21打卡 二叉树 part08 669. 修剪二叉搜索树 108. 将有序数组转换为二叉搜索树 538. 把二叉搜索树转换为累加树

news2024/11/14 23:13:09

代码随想录训练营 Day21打卡 二叉树 part08

一、 力扣669. 修剪二叉搜索树

给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
示例 :
在这里插入图片描述
输入:root = [1,0,2], low = 1, high = 2
输出:[1,null,2]

版本一 递归法

实现思路

  1. 首先检查当前节点是否为空,如果为空则返回空。
  2. 如果当前节点的值小于区间的下界,则修剪右子树,因为左子树的所有节点都小于当前节点,不可能符合条件。
  3. 如果当前节点的值大于区间的上界,则修剪左子树,因为右子树的所有节点都大于当前节点,不可能符合条件。
  4. 如果当前节点的值在区间范围内,则递归地修剪左右子树。
  5. 返回修剪后的当前节点。
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:
        # 如果当前节点为空,直接返回空
        if root is None:
            return None
        
        # 如果当前节点的值小于区间的下界low,那么整个左子树都不符合条件
        # 继续修剪右子树,寻找符合条件的节点
        if root.val < low:
            return self.trimBST(root.right, low, high)
        
        # 如果当前节点的值大于区间的上界high,那么整个右子树都不符合条件
        # 继续修剪左子树,寻找符合条件的节点
        if root.val > high:
            return self.trimBST(root.left, low, high)
        
        # 当前节点的值在区间范围内,继续修剪左右子树
        root.left = self.trimBST(root.left, low, high)  # 修剪左子树
        root.right = self.trimBST(root.right, low, high)  # 修剪右子树
        
        # 返回修剪后的当前节点
        return root

版本二 迭代法

实现思路

  1. 检查根节点是否为空,如果为空则返回空。

  2. 处理根节点,使其移动到区间 [L, R] 范围内。

    如果根节点的值小于L,则根节点需要移动到右子树,因为左子树所有节点都小于当前节点。
    如果根节点的值大于R,则根节点需要移动到左子树,因为右子树所有节点都大于当前节点。

  3. 处理左子树中的节点,使所有左子树的节点值都大于等于L。

    遍历左子树,如果左孩子节点的值小于L,则删除该左孩子节点,并让左孩子节点指向其右孩子节点。

  4. 处理右子树中的节点,使所有右子树的节点值都小于等于R。

    遍历右子树,如果右孩子节点的值大于R,则删除该右孩子节点,并让右孩子节点指向其左孩子节点。

  5. 返回处理后的根节点。

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def trimBST(self, root: TreeNode, L: int, R: int) -> TreeNode:
        if not root:
            return None
        
        # 处理头结点,让root移动到[L, R] 范围内
        while root and (root.val < L or root.val > R):
            if root.val < L:
                root = root.right  # 小于L往右走
            else:
                root = root.left  # 大于R往左走
        
        cur = root
        
        # 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
        while cur:
            while cur.left and cur.left.val < L:
                cur.left = cur.left.right  # 删除不符合条件的左孩子
            cur = cur.left
        
        cur = root
        
        # 此时root已经在[L, R] 范围内,处理右孩子大于R的情况
        while cur:
            while cur.right and cur.right.val > R:
                cur.right = cur.right.left  # 删除不符合条件的右孩子
            cur = cur.right
        
        return root

力扣题目链接
题目文章讲解
题目视频讲解

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

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 平衡 二叉搜索树。
示例 :
在这里插入图片描述
输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]

分割点就是数组中间位置的节点。

那么为问题来了,如果数组长度为偶数,中间节点有两个,取哪一个?

取哪一个都可以,只不过构成了不同的平衡二叉搜索树。

例如:输入:[-10,-3,0,5,9]

如下两棵树,都是这个数组的平衡二叉搜索树:
在这里插入图片描述
如果要分割的数组长度为偶数的时候,中间元素为两个,是取左边元素 就是树1,取右边元素就是树2。

这也是题目中强调答案不是唯一的原因。 理解这一点,这道题目算是理解到位了。

版本一 递归法

实现思路

  1. 定义一个辅助函数 traversal 用于递归构建树。
  2. 在 traversal 中,判断递归的终止条件,即 left 超过 right 时返回 None。
  3. 计算当前数组的中间元素位置 mid,并以该元素为根节点。
  4. 递归地构建左子树和右子树。
  5. 在 sortedArrayToBST 中调用 traversal 函数并返回构建的树的根节点。
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def traversal(self, nums: List[int], left: int, right: int) -> TreeNode:
        # 当左指针超过右指针时,返回空
        if left > right:
            return None
        
        # 计算中间位置
        mid = left + (right - left) // 2
        
        # 以中间元素为根节点
        root = TreeNode(nums[mid])
        
        # 递归构建左子树,范围是从left到mid-1
        root.left = self.traversal(nums, left, mid - 1)
        
        # 递归构建右子树,范围是从mid+1到right
        root.right = self.traversal(nums, mid + 1, right)
        
        # 返回当前根节点
        return root
    
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        # 从nums数组中创建高度平衡的二叉搜索树
        return self.traversal(nums, 0, len(nums) - 1)

版本二 递归法 精简

实现思路

  1. 判断数组是否为空,如果为空则返回 None。
  2. 计算数组的中间元素位置 mid,并以该元素为根节点。
  3. 递归地构建左子树和右子树。
  4. 左子树使用数组的前半部分(不包括中间元素),右子树使用数组的后半部分(不包括中间元素)。
  5. 返回构建的树的根节点。
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        # 如果数组为空,返回空
        if not nums:
            return None
        
        # 计算中间位置
        mid = len(nums) // 2
        
        # 以中间元素为根节点
        root = TreeNode(nums[mid])
        
        # 递归构建左子树
        root.left = self.sortedArrayToBST(nums[:mid])
        
        # 递归构建右子树
        root.right = self.sortedArrayToBST(nums[mid + 1:])
        
        # 返回当前根节点
        return root

版本三 迭代法

实现思路

  1. 判断数组是否为空,如果为空则返回 None。

  2. 创建根节点,并初始化队列用于存放节点及其对应的左右区间。

  3. 将初始根节点及其左右区间加入队列。

  4. 使用循环处理队列中的每个节点:

    取出当前节点和其对应的左右区间。
    计算中间位置,并设置当前节点的值为中间元素。
    如果左区间存在,创建左孩子节点并将其加入队列。
    如果右区间存在,创建右孩子节点并将其加入队列。

  5. 返回构建好的树的根节点。

from collections import deque

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        # 如果数组为空,返回空
        if len(nums) == 0:
            return None
        
        # 创建初始根节点
        root = TreeNode(0)
        
        # 队列用于存放待处理的节点
        nodeQue = deque()
        leftQue = deque()
        rightQue = deque()
        
        # 将初始节点和其对应的左右区间加入队列
        nodeQue.append(root)
        leftQue.append(0)
        rightQue.append(len(nums) - 1)

        # 处理队列中的每个节点
        while nodeQue:
            # 取出当前节点和其对应的左右区间
            curNode = nodeQue.popleft()
            left = leftQue.popleft()
            right = rightQue.popleft()
            
            # 计算中间位置
            mid = left + (right - left) // 2
            
            # 设置当前节点的值为中间元素
            curNode.val = nums[mid]

            # 如果左区间存在,创建左孩子节点并加入队列
            if left <= mid - 1:
                curNode.left = TreeNode(0)
                nodeQue.append(curNode.left)
                leftQue.append(left)
                rightQue.append(mid - 1)

            # 如果右区间存在,创建右孩子节点并加入队列
            if right >= mid + 1:
                curNode.right = TreeNode(0)
                nodeQue.append(curNode.right)
                leftQue.append(mid + 1)
                rightQue.append(right)

        # 返回构建好的树的根节点
        return root

力扣题目链接
题目文章讲解
题目视频讲解

三、 力扣538. 把二叉搜索树转换为累加树

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
    节点的左子树仅包含键 小于 节点键的节点。
    节点的右子树仅包含键 大于 节点键的节点。
    左右子树也必须是二叉搜索树。
示例 :
在这里插入图片描述
输入:[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]

从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了。

遍历顺序如图所示:
在这里插入图片描述
本题依然需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加。

版本一 递归法

实现思路

  1. 定义一个辅助变量 pre 来记录前一个节点的累加和。
  2. 定义一个辅助函数 traversal 用于递归遍历树。
  3. 采用反中序遍历(右-中-左)来遍历树,先处理右子树,再处理当前节点,最后处理左子树。
  4. 在每个节点,更新其值为当前值加上 pre,然后更新 pre 为当前节点的新值。
  5. 在 convertBST 中初始化 pre 并调用 traversal 函数,返回处理后的根节点。
# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def convertBST(self, root: TreeNode) -> TreeNode:
        self.pre = 0  # 记录前一个节点的累加和
        self.traversal(root)
        return root

    def traversal(self, cur: TreeNode):
        if cur is None:
            return
        
        # 先遍历右子树
        self.traversal(cur.right)
        
        # 更新当前节点的值
        cur.val += self.pre
        
        # 更新累加和
        self.pre = cur.val
        
        # 再遍历左子树
        self.traversal(cur.left)

版本二 迭代法

实现思路

  1. 初始化一个辅助变量 pre 来记录前一个节点的累加和。
  2. 定义一个辅助函数 traversal 用于迭代遍历树。
  3. 使用栈进行反中序遍历(右-中-左)。
  4. 在每个节点,更新其值为当前值加上 pre,然后更新 pre 为当前节点的新值。
  5. 在 convertBST 中初始化 pre 并调用 traversal 函数,返回处理后的根节点。
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def __init__(self):
        self.pre = 0  # 记录前一个节点的累加和
    
    def traversal(self, root: TreeNode):
        stack = []
        cur = root
        
        # 使用栈进行迭代遍历
        while cur or stack:
            if cur:
                # 先遍历右子树
                stack.append(cur)
                cur = cur.right
            else:
                # 处理当前节点
                cur = stack.pop()
                cur.val += self.pre
                self.pre = cur.val
                
                # 再遍历左子树
                cur = cur.left
    
    def convertBST(self, root: TreeNode) -> TreeNode:
        self.pre = 0  # 重置累加和
        self.traversal(root)
        return root

力扣题目链接
题目文章讲解
题目视频讲解

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

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

相关文章

密码学基础:搞懂Hash函数SHA1、SHA-2、SHA3(2)

目录 1.引入 2. SHA512-224\256 3.SHA-3 4.MD5 5.SM3 1.引入 上篇密码学基础&#xff1a;搞懂Hash函数SHA1、SHA-2、SHA3(1)-CSDN博客&#xff0c;我们先就将基础的SHA1\2讲解了&#xff0c;接下来我们继续聊SHA-3、SHA2变体SHA512_224\256等 2. SHA512-224\256 SHA512…

[oeasy]python0028_女性程序员_Eniac_girls_bug_Grace

028_第一个bug是谁发现的_编译之母 回忆上次内容 py文件 是 按照顺序 一行行 挨排 解释执行的 可以用 pdb3 hello.py 来调试程序 顺序执行 程序 在文本中 从上到下 是 一行行写的 解释器 从上到下 是 一行行解释的 调试 也是 从上到下 一行行 调试的 bug这个东西 是什么时候才有…

Rsync未授权访问漏洞

Rsync未授权访问漏洞 Rsync是Liux/Unix下的一个远程数据同步工具&#xff0c;可通过LAN/WAN快速同步多台主机间的文件和目录&#xff0c;默认运行在873端口。由于配置不当&#xff0c;导致任何人可未授权访问Syc,上传本地文件&#xff0c;下载服务器文件。RSyc默认允许匿名访问…

Java—继承和多态 (๑╹◡╹)ノ“““

目录&#xff1a; 一、继承&#xff1a; 为什么面向对象中有继承的概念&#xff1f;那么继承又是什么&#xff0c;继承又有什么作用呢&#xff1f;在我们生活中啊&#xff0c;也存在继承的关系&#xff0c;比如&#xff1a;你父母的财产由你“继承”。那在面向对象中&#xff…

vxe-pulldown 设置了宽度,并不能100%的占满整个容器的解决

1、下拉容器的使用 2、然而&#xff0c;这个宽度的显示是个问题&#xff0c;只占了一小部分&#xff1a; 长度并没有充满整个容器。 vxe-input设置了100%&#xff0c;然后也是一样的效果。 3、解决&#xff1a; .vxe-pulldown {width: 100% !important;} 增加上面的样式&…

本地GitLab runner自动编译Airoha项目

0 Preface/Foreword 1 GitLab runner环境 具体情况如下&#xff1a; Gitlab-ruuner运行在wsl 1中的Ubuntu 18.04 distro上专门为GitLab-runner分配了一个用户&#xff0c;名为gitlab-runner 2 自动编译 2.1 Permission denied 编译过程中&#xff0c;有两个文件出现权限不允…

Java语言程序设计基础篇_编程练习题*16.4 (创建一个英里/公里的转换器)

目录 *16.4 (创建一个英里/公里的转换器) 代码示例 结果展示 *16.4 (创建一个英里/公里的转换器) 编写一个程序来转换英里和公里&#xff0c;如图16-37b所示。如果在英里文本域Mile中输入一个值之后按下回车键&#xff0c;就会在公里文本域公里值。同样的&#xff0c;在公里文…

Latex入门指南:从下载到安装的全面教程

本篇博客旨在为初学者提供一个全面的Latex入门指南&#xff0c;涵盖了从下载、安装到配置Texlive和TexStudio的详细步骤。通过本指南&#xff0c;您将了解到如何正确安装Latex环境并成功运行第一个Latex文档&#xff0c;为撰写高质量的科技论文或书籍打下坚实基础。 目录 一定…

因为不懂ESLint,我被公司开除了……

你好,我是Qiuner. 为帮助别人少走弯路和记录自己编程学习过程而写博客 这是我的 github https://github.com/Qiuner ⭐️ ​ gitee https://gitee.com/Qiuner &#x1f339; 如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 &#x1f604; (^ ~ ^) 想看更多 那就点个关注吧 我…

把握现货黄金价格走势与买入时机 这两点缺一不可

在现货黄金投资中&#xff0c;对黄金价格走势的分析和做交易&#xff08;买入卖出&#xff09;&#xff0c;这些动作之间是相关联的&#xff0c;而且联系很大&#xff0c;比方说投资者如果没有对现货黄金价格走势做正确有效的分析&#xff0c;那他可能在一些交易中获得盈利&…

【附PDF】《大模型应用开发 动手做 AI Agent》,第一本给程序员看的AI Agent图书!

AI Agent火爆到什么程度&#xff1f; OpenAI创始人奥特曼预测&#xff0c;未来各行各业&#xff0c;每一个人都可以拥有一个AI Agent&#xff1b;比尔盖茨在2023年层预言&#xff1a;AI Agent将彻底改变人机交互方式&#xff0c;并颠覆整个软件行业&#xff1b;吴恩达教授在AI …

隧道通风网络节点图导出CAD文本时的三角形算法

在TESP软件中涉及到将带文本的节点图导出为CAD文件&#xff0c;其中文本的绘制需要根据Section的方向来确定&#xff0c;确保和绘图的习惯一致。具体包括&#xff1a; &#xff08;1&#xff09;垂直绘制的Section需确保文字字头向左。 &#xff08;2&#xff09;除了垂直的文…

Golang面试题三(map)

1.map底层实现 由图看出&#xff0c;其实map的底层结构体是hmap&#xff0c;同时hmap里面维护着若干个bucket数组&#xff08;即桶数组&#xff09;。bucket数组中每个元素都是bmap结构的&#xff0c;bmap中存储着8个key-value的键值对&#xff0c;如果是满了的话&#xff0c;当…

奥运会Ⅵ--LLM 是否狡猾到可以自行欺骗你?

这已经成为一句老生常谈&#xff0c;因为它是事实&#xff1a;人类开发的任何工具都可以用于行善或作恶。你可以用锤子敲钉子或砸某人的头。你可以用火取暖或烧毁房屋。等等。 因此&#xff0c;数字世界的最新工具既带来好处&#xff0c;也带来风险&#xff0c;这不足为奇。其…

文献解读-遗传病-第二十六期|《癫痫的临床特征、诊疗和KCNH5突变》

关键词&#xff1a;遗传病&#xff1b;基因测序&#xff1b;变异检测&#xff1b; 文献简介 标题&#xff08;英文&#xff09;&#xff1a;Clinical Feature, Treatment, and KCNH5 Mutations in Epilepsy标题&#xff08;中文&#xff09;&#xff1a;癫痫的临床特征、诊疗和…

文心一言 VS 讯飞星火 VS chatgpt (318)-- 算法导论22.3 10题

十、修改深度优先搜索的伪代码&#xff0c;让其打印出有向图G的每条边及其分类。并指出&#xff0c;如果图G是无向图&#xff0c;要进行何种修改才能达到相同的效果。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 首先&#xff0c;我们来定义深度优先搜索&…

leetcode:汇总区间

题目&#xff1a; 给定一个无重复元素的有序整数数组nums。返回恰好覆盖数组中所有数字的最小有序区间范围列表 。也就是说&#xff0c;nums的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某个范围但不属于nums的数字X。列表中的每个区间范围[a,b]应该按…

简单的docker学习 第2章 docker引擎

第2章docker引擎 2.1Docker 引擎发展历程 2.1.1 首发版本架构 Docker 在首次发布时&#xff0c;其引擎由两个核心组件构成&#xff1a;LXC&#xff08;Linux Container&#xff09;与 Docker Daemon。不过&#xff0c;该架构依赖于 LXC&#xff0c;使得 Docker 存在严重的问…

人力资源杂志人力资源杂志社人力资源编辑部2024年第13期目录

看法_总编随笔 学会退步 齐向宇; 1 看法_热点聚焦 数说 7 司事 9 看法_热点聚焦_翻转 话题 “霸总”发言遭吐槽对职场年轻人多些体谅 8 看法_视界《人力资源》投稿&#xff1a;cn7kantougao163.com 养老保险改革及其对人事工作的启示 赵梓安; 12-13 做…

潘展乐速度!滴滴无车赔,叫车就是快

8月5日&#xff0c;滴滴网约车“快”乐大使潘展乐在男子4x100米混合泳接力比赛中以45秒92的优异成绩在最后一棒反超&#xff0c;中国队夺得金牌&#xff01;恭喜潘展乐在本届比赛中和队友一起站上冠军的领奖台&#xff0c;用团队金牌为自己庆生&#xff01; 为进一步提升用户叫…