算法题:99.恢复二叉搜索树

news2024/11/24 19:25:45

(为不影响大家的观感,完整题目附在了最后)

二叉搜索树的定义

二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树。
二叉搜索树:一棵二叉树,可以为空;如果不为空,满足以下性质:

  1. 非空左子树的所有键值小于其根结点的键值。
  2. 非空右子树的所有键值大于其根结点的键值。
  3. 左、右子树都是二叉搜索树。

恢复二叉搜索树的解法分析

由二叉搜索树的定义可推知:二叉搜索树的中序遍历结果一定是严格由小到大排序的。由于“恢复二叉搜索树”的题目中指出“恰好两个节点的值被错误地交换”,那么我们只要找出破坏了这个顺序的两个节点,交换其节点值就可以了。

阅读本篇内容时,可结合本人在另一个博客中详细分析的 Morris 中序遍历方法:

算法:实现中序遍历(3种方法:递归、迭代、Morris)-CSDN博客

本题最优解法是采用 Morris 中序遍历方法,也就是题目进阶要求里的使用 O(1) 空间的解决方案,本人之前掌握的 Morris 中序遍历方法,在遍历的过程中是会改变树的结构的,会影响到层序遍历的结果,而本题要求的输出是层序遍历的,因此改变树的结构不可行。为此,我又学习了另一种最终不会改变树的结构的 Morris 中序遍历方法,我在这里重新贴一下代码,具体的原理分析还请看我上面分享的博文,那里面写的很详细,步骤都有画出来。

class Solution(object):
    def inorderTraversal(self, root):
        res = []
        while root:
            if root.left:
                temp = root.left
                while temp.right and temp.right != root:
                    temp = temp.right
                if not temp.right:
                    temp.right = root
                    root = root.left
                else:  # temp.right == root 的情况
                    res.append(root.val)
                    temp.right = None
                    root = root.right
            else:
                res.append(root.val)
                root = root.right
        return res

恢复二叉搜索树的完整代码

接下来,只要在其中加一些判断语句,找出中序遍历后不服从由小到大顺序的两个结点进行值的交换即可,完整测试代码如下:(提交时只需要提交recoverTree()函数代码,层序遍历的输出是力扣自动帮忙完成的)

# 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 recoverTree(self, root):
        x, y = None, None  # 设置两个变量,代表被错误交换的两个节点
        pre = None
        while root:
            if root.left:
                tmp = root.left
                while tmp.right and tmp.right != root:
                    tmp = tmp.right
                if tmp.right is None:
                    tmp.right = root
                    root = root.left
                else:  # temp.right == root 的情况
                    if pre and pre.val > root.val:  # 新加入的判断语句
                        # 假设最先遇到的两个不符合顺序的结点就是最终要找的两个节点
                        if not x:  
                            x = pre
                            y = root
                        else:  # 如果后面又遇到了不符合顺序的结点,则 y 需要变
                            y = root
                    pre = root
                    tmp.right = None
                    root = root.right
            else:
                if pre and pre.val > root.val:  # 新加入的判断语句
                    if not x:
                        x = pre
                        y = root
                    else:
                        y = root
                pre = root
                root = root.right

        if x and y:
            x.val = x.val ^ y.val
            y.val = x.val ^ y.val
            x.val = x.val ^ y.val

    def levelOrder(self, root):  # 层序排列
        if not root:
            return []
        res = []
        queue = [root]
        while len(queue) > 0:
            size = len(queue)
            temp = []
            for i in range(size):  # 确保了每层的结点值在同一个数组内
                # 通过append、pop(0)的方法用数组构造了一个先进先出的列表
                node = queue.pop(0)
                temp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(temp)

        return res


if __name__ == '__main__':
    # 创建一个二叉树
    tree = TreeNode(3)
    tree.left = TreeNode(1)
    tree.right = TreeNode(4)
    tree.right.left = TreeNode(2)

    # 执行中序遍历
    sol = Solution()
    sol.recoverTree(tree)
    print(sol.levelOrder(tree))  # [[2], [1, 4], [3]]

 如果对这里的层序遍历的代码感兴趣,可以看我的这篇博文:

算法题:二叉树的层序遍历-CSDN博客

恢复二叉搜索树的完整题目

给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 

示例 1:

输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 的左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

示例 2:

输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。

提示:

  • 树上节点的数目在范围 [2, 1000] 内
  • -2^31 <= Node.val <= 2^31 - 1

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用 O(1) 空间的解决方案吗?

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

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

相关文章

二叉树题目:在二叉树中增加一行

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;在二叉树中增加一行 出处&#xff1a;623. 在二叉树中增加一行 难度 5 级 题目描述 要求 给定一个二叉树的根结…

WiFi模块的环境可持续性:可再生能源、材料创新与碳足迹管理

随着数字化时代的到来&#xff0c;WiFi模块已经成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;这种便利也伴随着对环境的一定影响。本文将深入研究WiFi模块在环境可持续性方面的挑战和机遇&#xff0c;重点关注可再生能源的应用、材料创新以及碳足迹管理。 1. 可…

NB-IoT水表和LoRa水表有什么区别?

在众多物联网技术中&#xff0c;NB-IoT和LoRa脱颖而出&#xff0c;广泛应用于智能水表的制造。那么&#xff0c;这两种水表究竟有何区别呢&#xff1f;下面&#xff0c;小编来为大家详细的讲下NB-IoT和LoRa这两者的工作原理以及两者的区别之处&#xff0c;一起来看下吧&#xf…

图片路径名动态生成

写成这样也可以 :src"./src/assets/ScreenLeft/btn${isShowLeft ? Show : Hide}.png"为了节省开销&#xff0c;这种小图标&#xff0c;可以用i标签 const imgUrl ref("icon1");<iclass"w-50px h-50px":style"{backgroundImage: url(./…

老师们看过来,成绩发布原来可以这么简单

成绩发布不再让你头大&#xff01;不再需要每次都要手动查找学生成绩&#xff0c;浪费宝贵的休息时间!现在&#xff0c;只需要掌握一些小技巧&#xff0c;就能轻松实现学生自助查询成绩&#xff01; 引入数据库管理软件 可以引入一些数据库管理软件&#xff0c;例如MySQL、Pos…

Scala 泛型编程

1. 泛型 Scala 支持类型参数化&#xff0c;使得我们能够编写泛型程序。 1.1 泛型类 Java 中使用 <> 符号来包含定义的类型参数&#xff0c;Scala 则使用 []。 class Pair[T, S](val first: T, val second: S) {override def toString: String first ":" sec…

高压放大器的作用和优势是什么

高压放大器是一种专门用于放大高电压信号的设备&#xff0c;它具有许多重要的作用和优势。在以下的文章中&#xff0c;我们将详细介绍高压放大器的作用和优势。 高压放大器的作用之一是在实验室和工程应用中提供对高压信号的放大和控制。许多应用领域&#xff0c;如实验物理、电…

C/C++数据结构-链表-链表合并排序输出

文章目录 前言例题题解带头结点不带头结点 前言 这个小例题涵盖的知识点还是非常多的。包括链表的定义&#xff0c;链表的尾插法&#xff0c;链表的遍历&#xff0c;冒泡排序用链表实现。链表可以使用带头结点和不带头结点的形式&#xff0c;各有千秋。 本文完整版使用带头结点…

美团圈圈私域加群app拉新 单价高一手渠道整理

美团圈圈为我们现在主推产品 可以通过”聚量推客“ 申请推广 一手数据&#xff0c;外面很多其它的数据都会阉割的很厉害&#xff0c;可以对比 下面介绍下圈圈的优势&#xff0c;我们目前圈圈对外结算时间为11天&#xff08;因为美团官方有个要求 10天内退群无效&#xff09;&…

技能证里的天花板—阿里云云计算架构师ACE认证!

在当今的社会中&#xff0c;想要获得一份好工作、得到丰厚的报酬&#xff0c;唯一的方法就是证明自己优秀&#xff0c;能给公司创造价值&#xff0c;是大多数公司想要看到的。 那么在面试过程中&#xff0c;怎么样才能让面试官一眼就记住呢&#xff1f;那一定是有一份足够优秀…

Java生成二维码并打印二维码和文字信息

目录 1、生成二维码&#xff0c;并调用画布进行二维码和文字的描绘。 2、主程序&#xff1a;获取打印机&#xff0c;并打印内容 3、打印效果 参考文献&#xff1a; 前期工作是安装好打印机驱动&#xff0c;可连接打印机。 添加三个依赖jar&#xff1a; 具体见文底的参考文献…

什么情况会造成电表不走数?

电表是衡量用电量的重要设备&#xff0c;一旦出现不走数的情况&#xff0c;不仅会影响用户对用电量的准确计算&#xff0c;还可能造成电费纠纷。那么&#xff0c;究竟什么情况下会造成电表不走数呢&#xff1f;接下来&#xff0c;小编来为大家介绍下&#xff0c;一起来看下吧&a…

学习使用php实现汉字验证码

学习使用php实现汉字验证码 <?php //开启session &#xff0c;方便验证 session_start(); //创建背景画布 $image imagecreatetruecolor(200, 60); $background imagecolorallocate($image, 255, 255, 255); imagefill($image, 0, 0, $background);//创建背景画布 for ($…

【腾讯云HAI域探秘】AI让我变成灵魂画手

【腾讯云HAI域探秘】AI让我变成灵魂画手 文章目录 【腾讯云HAI域探秘】AI让我变成灵魂画手前言环境搭建进入 StableDiffusionWebUI使用 高性能应用服务HAI 部署的 StableDiffusionWebUI 快速进行AI绘画总结 前言 最近有幸参与了腾讯云举办的 腾讯云 HAI 产品体验活动。在这个过…

解决VS中文编译时出现:常量中有换行符

错误如下 首先确定文件编码格式已经是utf-8了&#xff0c;然后在有中文的情况的下&#xff0c;编译时会报错&#xff0c;真的很恶心 tabWidget.addTab(widget, tr("材料库"));tabWidget.addTab(widget1, tr("B"));解决方案 通过在项目里设置编译选项: /utf…

【docker使用Jar自定义镜像:基于windows】

在一个空文件夹中创建Dockerfile 将jar包复制到该路径下 在Dockerfile中添加以下内容 # 指定基础镜像 FROM java:8-alpine# 和java项目的包 COPY ./study_dockerfile-1.0.0.jar /tmp/app.jar# 暴露端口 EXPOSE 8081# 入口&#xff0c;java项目的启动命令 ENTRYPOINT java -jar…

开发ros一定要买树莓派吗?

结论&#xff1a;开发ros不一定要买树莓派&#xff0c;但是买一个会更方便&#xff0c;市场价410元/块&#xff1b; 开发ros机器人的时候&#xff0c;分为上位机和下位机2个控制中心&#xff0c; 其中下位机基本就是用STM32控制一个驱动电机。负责这个运动方向和速度。&#…

算法通关村第五关-白银挑战实现队列

大纲 队列基础队列的基本概念和基本特征实现队列队列的基本操作Java中的队列 队列基础 队列的基本概念和基本特征 队列的特点是节点的排队次序和出队次序按入队时间先后确定&#xff0c;即先入队者先出队&#xff0c;后入队者后出队&#xff0c;即我们常说的FIFO(first in fi…

感受野(Receptive Field)理解和计算

[Toc](感受野(Receptive Filed)的理解和计算) 感受野定义 在卷积神经网络中&#xff0c;感受野(Receptive Filed)是经过神经网络后生成的指特征图上的某个像素点所对应输入图像的区域。 针对上面的图&#xff0c;经过conv2 卷积神经网络后&#xff0c;生成了22 的特征图&…