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

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,一经查实,立即删除!

相关文章

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

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

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;数学上可以理…

【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…

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

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

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

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

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

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

力扣 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 文件编码改…

VS2019 QT无法打开 源 文件 “QTcpSocket“

VS2019 QT无法打开 源 文件 "QTcpSocket" QT5.15.2_msvc2019_64 严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E1696 无法打开 源 文件 "QTcpSocket" auto_pack_line_demo D:\vs_qt_project\auto_pack_line_de…

【区块链】truffle测试

配置区块链网络 启动Ganache软件 使用VScode打开项目的wordspace 配置对外访问的RPC接口为7545&#xff0c;配置项目的truffle-config.js实现与新建Workspace的连接。 创建项目 创建一个新的目录 mkdir MetaCoin cd MetaCoin下载metacoin盒子 truffle unbox metacoincontra…

如何减少Apache Spark日志的数量

修改log4j配置文件&#xff0c;没有就创建&#xff1a; 内容&#xff1a; # 设置日志记录器 log4j.rootCategoryWARN, console log4j.appender.consoleorg.apache.log4j.ConsoleAppender log4j.appender.console.targetSystem.err log4j.appender.console.layoutorg.apache.lo…

【栈】1096. 花括号展开 II

本文涉及知识点 栈 LeetCode 1096. 花括号展开 II 如果你熟悉 Shell 编程&#xff0c;那么一定了解过花括号展开&#xff0c;它可以用来生成任意字符串。 花括号展开的表达式可以看作一个由 花括号、逗号 和 小写英文字母 组成的字符串&#xff0c;定义下面几条语法规则&…

Python | Leetcode Python题解之第135题分发糖果

题目&#xff1a; 题解&#xff1a; class Solution:def candy(self, ratings: List[int]) -> int:n len(ratings)ret 1inc, dec, pre 1, 0, 1for i in range(1, n):if ratings[i] > ratings[i - 1]:dec 0pre (1 if ratings[i] ratings[i - 1] else pre 1)ret p…

通过 AI Edge Torch 生成式 API 在设备上使用自定义大语言模型

作者 / 首席工程师 Cormac Brick&#xff0c;软件工程师 Haoliang Zhang 我们很高兴地发布 AI Edge Torch 生成式 API&#xff0c;它能将开发者用 PyTorch 编写的高性能大语言模型 (LLM) 部署至 TensorFlow Lite (TFLite) 运行时&#xff0c;从而无缝地将新的设备端生成式 AI 模…

JavaSE中的if语句、switch语句:如何控制程序流程?

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

MySQL与PostgreSQL关键对比一(整体篇)

目录 1 快速参考表&#xff1a;MySQL 与 PostgreSQL 功能表 2 快速参考表&#xff1a;MySQL 与 PostgreSQL 功能表 MySQL 和 PostgreSQL 提供许多相同的特性和功能 - 但是这两个关系数据库管理系统 (RDBMS) 之间存在不容忽视的关键差异。 如果您不熟悉这些差异&#xff0c;这…