参数传递和剪枝,从修剪二叉树谈起

news2024/11/8 0:43:20

669. 修剪二叉搜索树 - 力扣(LeetCode)


一、参数传递

Java中的参数传递方式只有一种,那就是值传递。如果我们传的是基本数据类型,那么函数接收到的就是该数据的副本,如果我们传的是对象,那么函数接收到的就是该对象引用的副本。

对于值传递,由于函数拿到的是该值的副本,显然,对于此副本的任何修改不会对原值造成影响。

这里的关键之处在于:修改引用不会对原引用造成影响(因为引用是副本),修改引用指向的对象会对原引用指向的对象造成影响(因为函数中操作的对象不是原对象的副本)。

!!!想要对原引用造成影响,需要做的,是原引用接受函数改变后的副本的值。


二、例子(我的错误解)

在这个例子中,我犯的错误就是:混淆了引用和对象,认为函数中处理的TreeNode root是对象,其实是原对象引用的副本。

    public TreeNode trimBST1(TreeNode root, int low, int high) {
        trim(root, low, high);
        return root;
    }

    public void trim(TreeNode root, int low, int high) {
        if (root == null) return;

        if (root.val >= low && root.val <= high) {
            trim(root.left, low, high);
            trim(root.right, low, high);
        } else {
            if (root.left == null) {
                root = root.right;
                trim(root, low, high);
                return;
            }
            if (root.right == null) {
                root = root.left;
                trim(root, low, high);
                return;
            }
            TreeNode rightMinNode = root.right;
            while (rightMinNode.left != null) {
                rightMinNode = rightMinNode.left;
            }
            rightMinNode.left = root.left;
            root = root.right;
            trim(root, low, high);
        }
    }

让我截取其中的一段来说明这个问题:

            if (root.left == null) {
                root = root.right;
                return trimBST2(root, low, high);
            }

当root需要被修剪而它的左子树为null时,我的想法就是用它的右子树来替代它,并对替换后的子树做进一步修剪。

这个地方我操作的root,是原树的root节点的引用的副本,所以我这样操作,在这个局部root确实指向了它的右孩子节点,但函数结束之后,我用原引用对树进行遍历,会发现“修剪”根本没有生效,这就是因为我的“修剪”操作——尝试改变引用的方式,并没有影响到实际的引用。

下面这个图也许更加详细地说明了我的误解:

之所以会引起这个误解,是因为我们在写代码时,会很自然地认为我们在操作对象。这个说法当然没错,但需要注意的是,我们是通过引用在操作对象。在做具体的操作时,要注意这个操作是生效在引用上的,还是原来的对象上的。


三、剪枝

我对剪枝的理解就是,在进行业务处理之前通过判断避免不必要的处理以提升程序的效率。

下面是我的第二份代码,它解决了上面提到的问题,即只对引用的副本进行修改。

但是在对左右子树都存在的情况进行处理时,我这里是不管左右子树的大小,都默认进行处理。对于一颗较为复杂的树,这样的操作会引起栈溢出。

事实上,如果root.val已经小于low了,那么它的左子树也必然小于low,这样只需要对它的右子树进行接下来的操作并返回即可了。同样的,如果root.val也已经大于high了,那么只需要对它的左子树进行操作并返回。

    public TreeNode trimBST2(TreeNode root, int low, int high) {
        if (root == null) return null;

        if (root.val >= low && root.val <= high) {
            root.left = trimBST2(root.left, low, high);
            root.right = trimBST2(root.right, low, high);
        } else {
            if (root.left == null) {
                root = root.right;
                return trimBST2(root, low, high);
            }
            if (root.right == null) {
                root = root.left;
                return trimBST2(root, low, high);
            }
            TreeNode rightMinNode = root.right;
            while (rightMinNode.left != null) {
                rightMinNode = rightMinNode.left;
            }
            rightMinNode.left = root.left;
            root = root.right;
            return trimBST2(root, low, high);
        }
        return root;
    }

下面是第三份代码,解决了上面提到的参数传递和剪枝的问题,并把单子树的情况和多子树的情况不加区分地融入到剪枝的方案中,实现了最优解。

    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) return null;

        // 如果当前节点的值小于最小值,则说明该节点及其左子树都不符合要求,直接返回右子树
        // 注意此处返回的是对右子树修剪的结果,即此时的root是被“修剪”掉了
        if (root.val < low) {
            return trimBST(root.right, low, high);
        }
        // 同理,如果当前节点的值大于最大值,则说明该节点及其右子树都不符合要求,直接返回左子树
        // 通过直接返回对左子树修剪的结果,来实现“修剪”root的效果
        if (root.val > high) {
            return trimBST(root.left, low, high);
        }

        // 如果当前节点的值在[low, high]之间,则递归地对左右子树进行修剪
        root.left = trimBST(root.left, low, high);
        root.right = trimBST(root.right, low, high);

        return root;
    }

这里需要注意的一个细节就是,通过返回对右子树修剪的结果,并把这个结果替换掉原本指向根节点的引用,这个过程就已经抛弃了根节点,即完成了对根节点的修剪!

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

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

相关文章

Fortigate防火墙二层接口的几种实现方式

初始配置 FortiGate出厂配置默认地址为192.168.1.99&#xff08;MGMT接口&#xff09;&#xff0c;可以通过https的方式进行web管理&#xff08;默认用户名admin&#xff0c;密码为空&#xff09;&#xff0c;不同型号设备用于管理的接口略有不同。 console接口的配置 防火墙…

ubuntu certbot 生成https ssl证书

一、安装certbot应用 sudo apt update sudo apt install certbot python3-certbot-nginx二、生成证书 # 泛域名&#xff1a; certbot certonly -d *.你的主域名 --manual --preferred-challenges dns# 主域名&#xff1a; certbot certonly -d 你的主/子域名 --manual --pref…

单轴测径仪和双轴测径仪的区别

关键字&#xff1a;单轴测径仪、双轴测径仪、单轴双轴的结构差异、功能区别、应用场景、测量精度、测头、外径尺寸检测、 单轴测径仪和双轴测径仪在多个方面存在显著的区别&#xff0c;这些区别主要体现在其结构、功能、应用场景以及测量精度上。 首先&#xff0c;从结构上来…

水经微图IOS版5.3.0发布

随时随地&#xff0c;微图一下&#xff01; 水经微图&#xff08;以下简称“微图”&#xff09;IOS版&#xff0c;新版已上线。 当前版本 当前版本号为&#xff1a;5.3.0-beta 如果你发现该版本中存在问题&#xff0c;请及时反馈给我们修订。 关于我们产品的版本控制&…

猫毛过敏终极解决神器,使用宠物空气净化器享受快乐撸猫~

作为一位经验丰富的宠物主人&#xff0c;与猫咪共度的时光确实充满了乐趣。但是&#xff0c;猫毛和皮屑对某些人来说可能会成为头疼的问题&#xff0c;引发过敏症状&#xff0c;例如打喷嚏、流鼻涕&#xff0c;甚至呼吸急促。这些反应不仅会干扰宠物主人的日常生活&#xff0c;…

PPINtonus (深度学习音调分析)帕金森病早期检测系统

帕金森病&#xff08;Parkinson’s Disease&#xff0c;简称PD&#xff09;是一种主要影响运动功能的进行性神经退行性疾病。这种疾病主要是由于大脑中一个名为黑质&#xff08;substantia nigra&#xff09;的区域失去产生多巴胺的神经元而引起的。PD的主要运动症状包括震颤、…

C++笔试强训day40

目录 1.游游的字母串 2.体育课测验(二) 3.合唱队形 1.游游的字母串 链接https://ac.nowcoder.com/acm/problem/255195 英文字母一共就26个&#xff0c;因此可以直接暴力枚举以每个字母作为最后的转变字母。最后去最小值即可 #include <iostream> #include <cmath&…

商淘云电商分账系统如何为企业降低连锁财务成本

当今激烈的市场竞争中&#xff0c;连锁品牌企业面临着多样化的挑战&#xff0c;其中财务管理尤为关键。商淘云连锁收银系统作为一款专为连锁品牌量身定制的解决方案&#xff0c;不仅可以帮助企业实现总部入账管控财务、银行结算规范财务的目标&#xff0c;还能通过分账系统优化…

Linux系统安装APITable详细流程与远程访问本地平台数据分析

文章目录 前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 &#x1f4a1;推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击跳转到网站】 前言 v…

揭秘智能测径仪省钱之道!每年能为每条产线省上百万!

在当今竞争激烈的市场环境下&#xff0c;企业们都在不断寻求提高生产效率、降低成本的方法。而智能测径仪的出现&#xff0c;为圆形钢材、螺纹钢等生产企业实现这一目标提供了有力的支持。 智能测径仪被广泛应用于高线、铸管、圆钢、螺纹钢、钢筋等的轧制生产线中&#xff0c;进…

【Python】教你彻底了解Python中的并发编程

​​​​ 文章目录 一、并发编程的基本概念1. 线程&#xff08;Thread&#xff09;2. 进程&#xff08;Process&#xff09;3. 协程&#xff08;Coroutine&#xff09; 二、Python中的线程与进程1. 线程1.1 创建和启动线程1.2 线程同步 2. 多进程2.1 创建和启动进程2.2 进程间…

p2p文件传输小工具

使用webRTC的相关技术栈可以很轻松的开发一个p2p文件传输工具&#xff0c;这里主要讲下使用datachannel开发的一个文件传输工具client程序的使用 客户端A&#xff1a;需要可以访问公网&#xff0c;运行client的主机 客户端B&#xff1a;可以访问公网&#xff0c;可以和客户端…

关于三极管的理解

三极管工作时出现三个状态&#xff1a;截止、放大、饱和 1. 截止状态&#xff1a;三极管处于关断状态&#xff0c;Vce约等于电源电压 2. 放大状态&#xff1a;三极管处于电流放大状态&#xff0c;0V 3. 饱和状态&#xff1a;三极管处于完全导通状态&#xff0c;Vce≈0V 放大电…

卡尔曼滤波(Kalman Filtering)详细解读

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 卡尔曼滤波&#xff08;Kalman Filtering&#xff09;是一种用于估计…

天润酸奶爆改饭盒?为什么听劝营销“硬控”消费者如此有效

不知道大家会不会经常逛超市&#xff1f;有没有发现酸奶货架上有一道异于其它品牌的包装&#xff0c;它就是新疆天润酸奶&#xff0c;酷似饭盒的外包装对于当代倡导实用主义的年轻人来讲&#xff0c;这一发现无疑是直接“创进心巴”&#xff0c;不少网友表示它直接解决了带饭人…

新零售智能售卖教学实训沙盘内容介绍

新零售智能售卖教学实训沙盘是服务数据分析的教学工具。通过该沙盘&#xff0c;能够让学生了解数据分析在新零售行业智能售卖业务场景的应用流程。使用新零售智能售卖教学实训沙盘进行教学&#xff0c;一方面能够让老师的教学内容更加贴近实际应用&#xff0c;将教学场景具象化…

音视频开发13 FFmpeg 音频 相关格式分析 -- AAC ADTS格式分析

这一节&#xff0c;我们学习常用的音频的格式 AAC&#xff0c;重点是掌握 AAC的传输格式 ADTS 头部的信息&#xff0c;目的是 &#xff1a; 当音频数据有问题的时候&#xff0c;如果是AAC的编码&#xff0c;在分析 头部信息的时候能够根据头部信息 判断问题是否出现在 头部。 A…

搜狗输入法的软键盘怎么关闭

我的搜狗输入法软件盘和typora中ctrlshiftk冲突了&#xff0c;关闭软键盘

doris FE 在Windows环境下编译调试开发环境

前言&#xff1a; doris fe 在win下调试运行&#xff0c;和正常java项目有一些差异&#xff0c;主要是有与be&#xff08;c&#xff09;通信代码的生成 在win环境下不能直接生成&#xff0c;因此需要现在linux下生成之后&#xff0c;再拷贝到本地来&#xff0c;然后进行编译&a…

锻炼 精读笔记 01

元数据 [!abstract] 锻炼 书名&#xff1a; 锻炼作者&#xff1a; 丹尼尔利伯曼简介&#xff1a; 我们是为休息而生&#xff0c;还是为跑而生&#xff1f; 跑步会毁了你的膝盖吗? 哪种运动项目蕞适合我&#xff1f; 懒惰是不正常的行为吗&#xff1f; 每晚都需要睡够 8 个小时…