代码随想录训练营 Day18打卡 二叉树 part06 530. 二叉搜索树的最小绝对差 501. 二叉搜索树中的众数 236. 二叉树的最近公共祖先

代码随想录训练营 Day18打卡 二叉树 part06

一、 力扣530. 二叉搜索树的最小绝对差

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值
差值是一个正数,其数值等于两值之差的绝对值。
示例 :
在这里插入图片描述输入: root = [4,2,6,1,3]
输出: 1

我们需要用一个pre节点记录一下cur节点的前一个节点。如图:
在这里插入图片描述

版本一 递归法

首先将二叉搜索树的所有节点值转换为一个有序数组,然后计算数组中连续元素的最小差值。

class Solution:def __init__(self):self.vec = []  # 存储中序遍历结果的数组def traversal(self, root):"""中序遍历二叉搜索树,保证遍历结果的数组是有序的。"""if root is None:returnself.traversal(root.left)  # 访问左子树self.vec.append(root.val)  # 将节点值加入数组self.traversal(root.right)  # 访问右子树def getMinimumDifference(self, root):"""计算二叉搜索树中任意两个不同节点值之间的最小差值。"""self.vec = []  # 重置数组self.traversal(root)  # 执行中序遍历if len(self.vec) < 2:return 0  # 如果数组中的元素少于2个,直接返回0result = float('inf')for i in range(1, len(self.vec)):result = min(result, self.vec[i] - self.vec[i - 1])  # 计算相邻元素之间的最小差值return result

版本二 递归法

直接在中序遍历过程中计算最小差值,避免了使用额外的数组存储。

class Solution:def __init__(self):self.result = float('inf')  # 初始化最小差值为无穷大self.pre = None  # 用于存储上一个访问的节点def traversal(self, cur):"""递归中序遍历并更新最小差值。"""if cur is None:returnself.traversal(cur.left)if self.pre is not None:self.result = min(self.result, cur.val - self.pre.val)  # 更新最小差值self.pre = cur  # 更新前一个节点self.traversal(cur.right)def getMinimumDifference(self, root):self.traversal(root)return self.result

版本三 迭代法

使用迭代的方式执行中序遍历,并在遍历过程中计算最小差值。

class Solution:def getMinimumDifference(self, root):stack = []  # 使用栈来管理迭代过程中的节点cur = root  # 当前访问的节点pre = None  # 上一个访问的节点result = float('inf')  # 初始化最小差值为无穷大while cur is not None or len(stack) > 0:if cur is not None:stack.append(cur)  # 将当前节点加入栈中cur = cur.left  # 移至左子节点else:cur = stack.pop()  # 从栈中取出节点进行处理if pre is not None:result = min(result, cur.val - pre.val)  # 更新最小差值pre = cur  # 更新前一个节点cur = cur.right  # 移至右子节点return result

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

二、 力扣501. 二叉搜索树中的众数

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
假定 BST 满足如下定义:
    结点左子树中所含节点的值 小于等于 当前节点的值
    结点右子树中所含节点的值 大于等于 当前节点的值
    左子树和右子树都是二叉搜索树
示例 :
在这里插入图片描述
输入: root = [1,null,2,2]
输出: [2]

版本一 递归法:利用字典

使用字典来存储每个元素的出现次数,并通过遍历字典来确定哪些元素的出现频率最高。

from collections import defaultdictclass Solution:def searchBST(self, cur, freq_map):"""递归遍历树并统计每个值的出现次数。参数:- cur: 当前访问的节点- freq_map: 字典,用于记录每个值的出现次数"""if cur is None:return  # 递归基:如果当前节点为空,则返回freq_map[cur.val] += 1  # 增加当前节点值的计数self.searchBST(cur.left, freq_map)  # 递归遍历左子树self.searchBST(cur.right, freq_map)  # 递归遍历右子树def findMode(self, root):"""找出BST中的众数。返回具有最高频率的元素列表。"""freq_map = defaultdict(int)  # 使用字典记录元素频率result = []if root is None:return result  # 如果根节点为空,直接返回空列表self.searchBST(root, freq_map)  # 填充频率字典max_freq = max(freq_map.values())  # 获取最大频率for key, freq in freq_map.items():if freq == max_freq:  # 筛选出最大频率的元素result.append(key)return result

版本二 递归法:利用二叉搜索树性质

详细思路

  1. 初始化状态变量:

    self.maxCount: 用来记录遍历过程中遇到的最大的元素频率。
    self.count: 用于记录当前遍历的元素的连续出现次数。
    self.pre: 指向上一个访问的节点,用于比较当前节点和上一个节点的值。
    self.result: 用来存储频率最高的元素列表。

  2. 中序遍历实现:

        使用递归方法进行中序遍历,这意味着首先处理左子树,然后处理当前节点,最后处理右子树。
        在处理当前节点之前,左子树的所有元素已经被处理,这保证了元素的访问顺序是从小到大。

  1. 计算元素频率:

    当遍历到一个新节点时,首先检查它是否与前一个节点的值相同。
    如果与前一个节点值相同,则增加self.count的值。
    如果不同,说明遇到了一个新的元素,因此需要重置self.count为1。

  2. 更新众数和频率记录:

    在每次更新self.count后,比较self.count和self.maxCount。
    如果self.count大于self.maxCount,这意味着找到了一个更频繁的元素,因此更新self.maxCount为新的self.count,并且重置self.result为仅包含当前节点的值。
    如果self.count等于self.maxCount,将当前节点的值添加到self.result中,因为它的出现频率与目前已知的最高频率相同。

  3. 递归的连续性:

    继续递归调用处理右子树,保持中序遍历的连续性。
    遍历完成后,所有元素都被按照上述逻辑处理过,self.result将包含所有的众数。

  4. 返回结果:

    完成整棵树的遍历后,self.result中存储的就是所有出现频率最高的元素。
    返回self.result作为函数的输出。

class Solution:def __init__(self):self.maxCount = 0  # 记录最大频率self.count = 0  # 当前遍历元素的计数self.pre = None  # 前一个节点self.result = []  # 存储结果的列表def searchBST(self, cur):"""递归遍历BST,同时计算众数。使用中序遍历保证元素从小到大访问。"""if cur is None:returnself.searchBST(cur.left)if self.pre is None or self.pre.val != cur.val:self.count = 1  # 如果当前元素与前一个元素不同,则重置计数器else:self.count += 1  # 否则增加计数器if self.count > self.maxCount:  # 如果当前元素计数超过之前的最大频率self.maxCount = self.count  # 更新最大频率self.result = [cur.val]  # 重置结果列表为当前元素elif self.count == self.maxCount:self.result.append(cur.val)  # 如果当前元素频率等于最大频率,加入结果列表self.pre = cur  # 更新前一个节点为当前节点self.searchBST(cur.right)def findMode(self, root):self.searchBST(root)return self.result

版本三 迭代法

使用栈实现中序遍历的迭代方式,同时在遍历过程中更新众数的计数。

class Solution:def findMode(self, root):"""使用栈实现的迭代中序遍历,找出BST中的众数。返回具有最高频率的元素列表。"""st = []  # 栈用于存储节点,实现迭代中序遍历cur = rootpre = None  # 前一个节点maxCount = 0  # 最大频率count = 0  # 当前元素频率计数result = []  # 结果列表while cur is not None or st:while cur is not None:  # 移动到最左边st.append(cur)  # 将节点压入栈cur = cur.leftcur = st.pop()  # 从栈中取出节点if pre is None or pre.val != cur.val:count = 1  # 重置计数器else:count += 1  # 增加计数器if count > maxCount:maxCount = count  # 更新最大频率result = [cur.val]  # 重置结果列表elif count == maxCount:result.append(cur.val)  # 如果当前频率与最大频率相同,加入结果列表pre = cur  # 更新前一个节点cur = cur.right  # 移动到右子节点return result

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

三、 力扣236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 :
在这里插入图片描述
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。
即情况一:
在这里插入图片描述
但很多人容易忽略一个情况,就是节点本身p(q),它拥有一个子孙节点q§。 情况二:
在这里插入图片描述
其实情况一 和 情况二 代码实现过程都是一样的,也可以说,实现情况一的逻辑,顺便包含了情况二。

因为遇到 q 或者 p 就返回,这样也包含了 q 或者 p 本身就是 公共祖先的情况。

递归三部曲

  1. 确定递归函数的返回值和参数:

    参数:当前节点 root,节点 p 和 q。
    返回值:树中节点 p 和 q 的最低公共祖先。

  2. 确定终止条件:

    如果当前节点为空,返回 None。
    如果当前节点等于 p 或 q,返回当前节点。

  3. 确定单层递归逻辑:

    对当前节点的左子树和右子树分别进行递归。
    根据左右子树的返回值判断当前节点是否是 p 和 q 的最低公共祖先:
        如果左右子树递归结果都非空,返回当前节点。
        如果其中一侧为空,返回非空的一侧。
        如果两侧都为空,返回 None。

版本一 递归法

这个版本是典型的递归解法,利用了分治的思想来找到二叉树中两个节点(p 和 q)的最低公共祖先(LCA)。

class Solution:def lowestCommonAncestor(self, root, p, q):# 如果当前节点为空,或者等于p或q,则返回当前节点if root is None or root == p or root == q:return root# 递归查找左子树中的最低公共祖先left = self.lowestCommonAncestor(root.left, p, q)# 递归查找右子树中的最低公共祖先right = self.lowestCommonAncestor(root.right, p, q)# 如果左右子树的递归调用都返回了非空节点,说明p和q在root的两侧,root就是LCAif left is not None and right is not None:return root# 如果只有右子树递归返回非空,说明LCA在右子树if left is None and right is not None:return right# 如果只有左子树递归返回非空,说明LCA在左子树elif left is not None and right is None:return left# 如果左右子树递归都返回空,说明当前子树中没有p和q,返回Noneelse:return None

版本二 递归法 精简

这个版本精简了代码,去掉了一些冗余的条件判断,使逻辑更直接。

class Solution:def lowestCommonAncestor(self, root, p, q):# 如果当前节点为空,或者等于p或q,则返回当前节点if root is None or root == p or root == q:return root# 递归查找左子树中的最低公共祖先left = self.lowestCommonAncestor(root.left, p, q)# 递归查找右子树中的最低公共祖先right = self.lowestCommonAncestor(root.right, p, q)# 如果左右子树的递归调用都返回了非空节点,说明p和q在root的两侧,root就是LCAif left is not None and right is not None:return root# 如果左子树为空,返回右子树的结果;否则返回左子树的结果return right if left is None else left

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

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

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

相关文章

spring boot + vue3 接入钉钉实现扫码登录

1&#xff1a;准备工作 1.1&#xff1a;进入钉钉开放平台创建开发者应用。应用创建和类型介绍&#xff0c;参考下方。 应用类型介绍 - 钉钉开放平台 (dingtalk.com) 应用能力介绍 - 钉钉开放平台 (dingtalk.com) 扫码登录第三方网站 - 钉钉开放平台 (dingtalk.com) 1.2&…

KaiwuDB 产品总监李月飞:让中国物联网用上放心的数据库产品

​2024年7月17日&#xff0c;KaiwuDB 产品总监李月飞受邀于 2024 可信数据库发展大会“能源与政务数据库应用创新”分论坛发表演讲。以下是李月飞主题演讲《深耕数据良田&#xff0c;KaiwuDB 洞见能源产业数字新生力》精华实录。 数据&#xff0c;给能源变革带来新的可能 众所…

TypeScript 简介

文档 typeScript官网中文文档&#xff1a;https://www.tslang.cn/index.html中文文档(简洁点)&#xff1a;https://typescript.bootcss.comMDN 前言 JavaScript 引入编程社区已有 20 多年&#xff0c;如今已成为有史以来使用最广泛的跨平台语言之一。JavaScript 最初是一种用…

SSL VPN详细概述

为什么会出现SSL VPN呢&#xff1f;在这之前不是有IPSEC VPN吗&#xff1f; 通过这两个问题我们可以发现多半是IPSEC VPN在某些方面肯定有所欠缺&#xff0c;所以后面在出现了SSL VPN。 之前说过根据组网方式划分&#xff0c;可以分为 client to LAN 和 LAN to LAN 两种 而…

CTF学习笔记汇总(非常详细)零基础入门到精通,收藏这一篇就够了

CTF学习笔记汇总 Part.01 Web 01 SSRF 主要攻击方式如下&#xff1a; 01 对外网、服务器所在内网、本地进行端口扫描&#xff0c;获取一些服务的banner信息。 02 攻击运行在内网或本地的应用程序。 03 对内网Web应用进行指纹识别&#xff0c;识别企业内部的资产信息。 …

深入分析 Android ContentProvider (十二)

文章目录 深入分析 Android ContentProvider (十二)Android 中 ContentProvider 的系统代码分析&#xff08;续&#xff09;1. ContentProvider 的内部实现机制1.1. ContentProvider 的创建与生命周期管理1.2. ContentProvider 的数据访问与处理1.3. ContentProvider 的权限管理…

Go语言---sync.WaitGroup

在Go语言中&#xff0c;给我们提供了用于线程同步的sync.WaitGroup&#xff0c;简单来讲&#xff0c;WaitGroup就是指等待一组&#xff0c;等待一个系列执行完成后才会继续向下执行。 WaitGroup数据结构 type WaitGroup struct {noCopy noCopystate atomic.Uint64 // 高 32 b…

无人驾驶的未来:AI如何重塑我们的出行世界

无人驾驶汽车&#xff0c;作为人工智能&#xff08;AI&#xff09;技术的集大成者&#xff0c;正以前所未有的速度改变着我们的出行方式。从机器学习到计算机视觉&#xff0c;再到人工智能生成内容&#xff08;AIGC&#xff09;&#xff0c;AI技术的每一次进步都在为无人驾驶汽…

华为手机连接电脑后电脑无反应、检测不到设备的解决方法

本文介绍华为手机与任意品牌电脑连接时&#xff0c;出现连接后电脑无反应、检测不到手机连接情况的解决方法。 最近&#xff0c;因为手机的存储空间愈发紧缺&#xff0c;所以希望在非华为电脑中&#xff0c;将华为手机内的照片、视频等大文件备份、整理一下。因此&#xff0c;需…

公司里的IT是什么?

公司里的IT是什么&#xff1f; 文章目录 公司里的IT是什么&#xff1f;1、公司里的IT2、IT技术3、IT行业4、IT行业常见证书 如果对你有帮助&#xff0c;就点赞收藏把&#xff01;(&#xff61;&#xff65;ω&#xff65;&#xff61;)&#xff89;♡ 前段时间&#xff0c;在公…

《Windows API每日一练》24.1 WinSock简介

本节将逐一介绍WinSock的主要特性和组件&#xff0c;套接字、WinSock动态库的使用。 本节必须掌握的知识点&#xff1a; Windows Socket接口简介 Windows Socket接口的使用 第178练&#xff1a;网络时间校验 24.1.1 Windows Socket接口简介 ■以下是WinSock的主要特性和组件…

实时转换,轻松编辑:2024年高效语音转文字解决方案

现在生活节奏越来越快了&#xff0c;很多时候一场会议内容的信息量就会呈几何式增长。用笔来记录肯定来不及&#xff0c;那还有一个方法就是录音或者录像。录制完成后我们可以使用语音转文字来快速获取会议内容是不是就方便了很多。 1.365在线转文字 链接传送&#xff1a;ww…

华为云依赖引入错误

问题&#xff1a;记录一次项目加载华为云依赖错误&#xff0c;如下&#xff1a; 错误信息&#xff1a;Could not find artifact com.huawei.storage:esdk-obs-java:pom:3.1.2.1 in bintray-qcloud-maven-repo (https://dl.bintray.com/qcloud/maven-repo/) 找到本地仓库&#…

【practise】string_atoi

今天来分享一道比较平常的练习题&#xff0c;说实话我自己写了半天&#xff0c;自己写的很烂最后还是看的答案… 1.题目概要 题目链接&#xff1a;LINK 2.题目难点 这个题目有两个难点&#xff0c;如下&#xff1a; 拿到了全部都是数字字符的字符串&#xff0c;怎么将这个…

从技术角度解读【与辉同行】文案(一)

视频文字内容 标题&#xff1a;走晋.山西 内容&#xff1a;将一段岁月熔成佳酿&#xff0c;三晋儿女荡气回肠。捧一把黄土架起火柴&#xff0c;华夏大地照亮火光。五千年黄土风云&#xff0c;历代千秋根固魂盈。三万顷汾河烟雨&#xff0c;唐风宋韵人杰地灵。当先辈手持石器抛挖…

秘密打造「AI陶哲轩」 震惊数学圈!谷歌IMO梦之队首曝光,菲尔兹奖得主深度点评

谷歌DeepMind正在做的&#xff0c;是要打造出世界上最强的AI数学家。 Perplexity AI的CEO对此做出了大胆预测——DeepMind继续研究下去的话&#xff0c;应该可以搞出一个「AI陶哲轩」了&#xff01; 这个预测可谓相当大胆。 要知道&#xff0c;陶哲轩在IMO竞赛圈&#xff0c;乃…

ADI - 通过5 V至24 V输入提供双极性、双向DC-DC流入和流出电流

大部分电子系统都依赖于正电压轨或负电压轨&#xff0c;但是有些应用要求单电压轨同时为正负电压轨。在这种情况下&#xff0c;正电源或负电源由同一端子提供&#xff0c;也就是说&#xff0c;电源的输出电压可以在整个电压范围内调节&#xff0c;并且可以平稳转换极性。例如&a…

【CORS 报错】跨域请求问题:CORS 多种环境下的解决方案

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、CORS错误的常见原因二、解决方案1. Vue3 Vite项目下的解决方案创建Vue3 Vite项目配置Vite的代理发送请求 2. jQuery项目下的解决方案使用CORS请求头使用JSONP 3. 其他环境下的解决方案使用服务器端代理设置CORS头使用…

“再来一单“业务功能开发

文章目录 概要整体架构流程技术细节小结 概要 再来一单”功能常见于餐饮、零售、外卖等行业&#xff0c;主要目的是为了简化用户的重复购买流程&#xff0c;提高用户体验和效率。 需求分析以及接口设计 再来一单就是将原订单中的商品重新加入到购物车中,所以本质上是"增…

java之WIFI信号模块

开发步骤分为以下几点&#xff1a; 1.在 AndroidManifest 中声明相关权限&#xff08;网络和文件读写权限&#xff09; 声明权限: <uses-permission android:name"android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name"android.…