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

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.mzph.cn/pingmian/23772.shtml

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

相关文章

Uniapp与第三方应用数据通讯

首先说明一点&#xff0c;这个只是uniapp代码编写的应用之间相互传递数据&#xff0c;uniapp编写的与其他语言编写的我尚不知道能不能传递。 应用1&#xff1a; plus.runtime.launchApplication({pname: "应用的appid",// extra 中可以自定数据&#xff0c;url和da…

【Qt知识】部分QWidget属性表格

QWidget是Qt库中所有图形用户界面组件的基类&#xff0c;它提供了大量属性以供自定义和配置控件的行为和外观。下面列出了一些主要的QWidget属性及其作用。 属性 作用 accessibleName 控件的辅助技术名称&#xff0c;用于无障碍访问。 accessibleDescription 控件的辅助技…

详解MySQL的间隙锁

MySQL 的间隙锁&#xff08;Gap Lock&#xff09; 间隙锁&#xff08;Gap Lock&#xff09;是 InnoDB 存储引擎中的一种锁机制&#xff0c;用于防止幻读现象。幻读是指在一个事务中&#xff0c;两次读取同一个范围的数据时&#xff0c;第二次读取出现了第一次没有出现的数据行…

CSS真题合集(一)

CSS真题合集&#xff08;一&#xff09; 1. 盒子模型1.1 盒子模型的基本组成1.2 盒子模型的实际大小1.3 盒子模型的两种类型1.4 设置盒子模型1.5 弹性盒子模型 2. BFC2.1 主要用途2.2 触发BFC的方法2.2 解决外边距的塌陷问题&#xff08;垂直塌陷&#xff09; 3. 响应式布局3.1…

接口自动化框架封装思想建立(全)

httprunner框架&#xff08;上&#xff09; 一、什么是Httprunner&#xff1f; 1.httprunner是一个面向http协议的通用测试框架&#xff0c;以前比较流行的是2.X版本。 2.他的思想是只需要维护yaml/json文件就可以实现接口自动化测试&#xff0c;性能测试&#xff0c;线上监…

spring aop小记

一、aop概念 面向切面编程 参考&#xff1a;https://blog.csdn.net/lhj520cb/article/details/125820513 常用术语解释&#xff08;根据代码理解的&#xff09;&#xff1a; Aspect(切面)&#xff1a;Advice 通知(即增强)和 Pointcut 切点的结合。&#xff08;数学上可以理…

#define 和 const 定义常量的区别

文章目录 一、数组定义1.1 全局作用域中定义数组1.2 局部作用域定义数组 二、细节补充2.1 #define 和 const 的区别2.2 全局数组和局部数组的区别2.3 编译时常量 vs 运行时常量2.4 为什么局部作用域不要求编译时常量 总结 一、数组定义 1.1 全局作用域中定义数组 在全局作用域…

【Android面试八股文】Java异常机制中,异常Exception与错误Error区别是什么?

Java异常机制中,异常Exception与错误Error区别是什么? 这道题想考察什么? 在开发时需要时候需要自定义异常时,应该选择定义Excption还是Error? 编写的代码触发Excption或者Error分别代表什么? 考察的知识点 Java异常机制 考生应该如何回答 在Java中存在一个 Throwa…

Git - 详解 创建一个新仓库 / 推送现有文件夹 / 推送现有的 Git 仓库 到私有Gitlab

文章目录 【推送现有文件夹】详细步骤指令说明Git 全局设置设置Git全局用户名设置Git全局电子邮件地址 推送现有文件夹1. 进入现有文件夹2. 初始化Git仓库并设置初始分支为main3. 添加远程仓库4. 添加所有文件到暂存区5. 提交更改6. 推送代码到远程仓库并设置上游分支 创建一个…

ESXi内安装OpenWrt

目录 0、前言 1、环境 2、转换格式 3、创建虚拟机 4、OpenWrt设置 5、单臂流量测试 6、总结 0、前言 前几天在ESXi中先安装了PVE,然后在PVE中安装OpenWrt,没有来得及深入测试,仅仅作为安装和熟悉PVE的过程。后来转念一想为什么不在ES…

js之this

最近写代码学习了this&#xff0c;这个非常好用啊&#xff0c;今天拿出来给大家分享一下&#xff0c;根据我的理解以及前辈们的讲解 this 关键字代表当前执行上下文中的对象。它通常指向调用函数的对象&#xff0c;但其值可能取决于函数的调用方式。 全局上下文中的 this&…

项目经验,用什么思路去叙述?

文章目录 前言一、项目经验二、关于自学 前言 如果你的项目掌握的不高&#xff0c;面试官对项目的拷打&#xff0c;hold不住怎么办&#xff1f;首先一定要把项目说通透&#xff0c;一定要会说&#xff0c;就算可能没真实做过一个项目&#xff0c;会说出来讲通透就行。写在简历…

CS1061 “HtmlHelper”未包含“Partial”的定义,并且找不到可接受第一个“HtmlHelper”类型参数的可访问扩展方法“Partial”

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 CS1061 “HtmlHelper”未包含“Partial”的定义&#xff0c;并且找不到可接受第一个“HtmlHelper”类型参数的可访问扩展方法“Partial”(是否缺少 using 指令或程序集引用?) 14_Views_Message_E…

找嵌入式软件工作,freertos要掌握到什么程度?

对于嵌入式软件工程师来说&#xff0c;掌握RTOS&#xff08;实时操作系统&#xff09;的程度并不是决定性因素&#xff0c;而更重要的是工程思维和解决问题的能力。我这里有一套嵌入式入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习嵌入式…

GitHub个人访问令牌登录

生成个人访问令牌 登录 GitHub。访问 Personal Access Tokens 页面。点击 “Generate new token”。为令牌选择一个描述性名称。选择 repo 权限。点击 “Generate token” 生成令牌。复制生成的令牌。 推送命令 设置存储库 URL&#xff08;如果需要&#xff09;&#xff1a;…

Angular封装高德地图组件实现输入框搜索,地图点击选地点

Angular封装高德地图组件实现输入框搜索,地图点击选地点(Angular17版本) 话不多说直接上代码 创建一个独立组件 html代码: <div style"position: relative;"><input #searchInput nz-input placeholder"请输入地址"/><div #mapContaine…

PostgreSql创建数据库,用户以及权限分配

1.创建用户 CREATE USER newuser WITH PASSWORD password;2.创建数据库 CREATE DATABASE newdatabase;3.给用户赋权 GRANT ALL PRIVILEGES ON DATABASE newdatabase TO newuser;给用户newuser数据库(newdatabase)的所有权限

vue3之基于el-image实现图片预览

实现的功能&#xff1a; 图片可放大预览&#xff0c;支持放大、缩小、向左向右旋转查看可点击任意一张图后进行左右切换查看大图 主要使用的方法&#xff1a;splice和concat 主要代码 // template中 <div><el-imagev-for"(item, index) in imgsData":src&q…

力扣 48.旋转图像

题目描述&#xff1a; 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],…

CLion配置

下载环境&#xff1a;MinGW-w64 - for 32 and 64 bit Windows - Browse Files at SourceForge.net 解压后找一个位置存放&#xff0c;一般放在和ide同一目录&#xff0c;方便查找 个人习惯配置调整&#xff1a; 项目创建 修改ide解码形式 项目右下角一般默认是utf8 文件编码改…