Swift 解 LeetCode 250:搞懂同值子树,用递归写出权限系统检查器


文章目录
- 前言
- 问题描述简单说:
- 痛点分析:到底难在哪?
- 1. 子树的概念搞不清楚
- 2. 要不要“递归”?递归从哪开始?
- 3. 怎么“边遍历边判断”?这套路不熟
- 后序遍历 + 全局计数器
- 遍历过程解释一下:
- 和实际场景结合下:这题能学到啥?
- 文件系统权限继承检查
- 配置项一致性检查
- 时间复杂度
- 测试用例简单跑一下:
- 最后的话
前言
你有没有碰到过这种情况:给你一棵二叉树,要求你找出其中所有“节点值都相同的子树”数量。第一次看到是不是有点懵?我当时就反应了一下:子树、节点值一样、还要统计数量……这到底要怎么下手?

今天我们就来聊聊这道 LeetCode 第 250 题《统计同值子树(Count Univalue Subtrees)》,顺便结合点实际开发中可能遇到的场景,看看这种题到底能学到什么有用的思维方式。
问题描述简单说:
给你一棵二叉树,统计里面有多少个子树,它的所有节点值都一样。
举个例子:
5/ \1 5/ \ \
5 5 5
上面这个树中,有 4 个“同值子树”:最下面 3 个 5 叶子节点 + 右边那棵 5 -> 5 的子树。
痛点分析:到底难在哪?
这道题看起来像是一道“树的遍历”基础题,但实则不太好掌握。
1. 子树的概念搞不清楚
不少人一开始以为是“叶子节点”才叫子树,或者以为只有完整子结构才算。其实任意节点为根的结构都可以是子树。
2. 要不要“递归”?递归从哪开始?
树的问题很多时候都用递归,但递归是“从顶向下”还是“从底向上”?这题其实是要“从叶子往上走”,因为你得先知道左右子树是否满足条件,才能判断当前节点是不是一个“同值子树”。
3. 怎么“边遍历边判断”?这套路不熟
你不能等遍历完再判断,而是要在每次递归返回的时候就带点有用的信息,比如:是不是同值,是的话加一。

后序遍历 + 全局计数器
class TreeNode {var val: Intvar left: TreeNode?var right: TreeNode?init(_ val: Int) {self.val = val}
}class Solution {private var count = 0func countUnivalSubtrees(_ root: TreeNode?) -> Int {_ = isUnival(root)return count}private func isUnival(_ node: TreeNode?) -> Bool {guard let node = node else {return true // 空节点默认算同值子树}let leftIsUnival = isUnival(node.left)let rightIsUnival = isUnival(node.right)if !leftIsUnival || !rightIsUnival {return false}if let left = node.left, left.val != node.val {return false}if let right = node.right, right.val != node.val {return false}count += 1return true}
}
逻辑很简单:
- 用一个
count全局变量做计数器 - 用一个递归函数
isUnival判断某节点是不是“同值子树” - 每次判断成功就给计数器加一
遍历过程解释一下:
拿刚才的例子图来说:
5/ \1 5/ \ \5 5 5
从最下面开始判断:
- 左下两个
5是叶子节点,肯定是同值子树 - 1 的左右子树虽然都是
5,但跟自己不一样,所以不是 - 右边的
5 -> 5是同值 - 整棵树不是,因为左子树不满足
最后统计出来就是 4 个。
和实际场景结合下:这题能学到啥?
说实话,单纯为了刷题记住这题的套路没啥意思。咱们可以想一想,在日常开发中,有没有遇到类似的结构需求?答案是:有。
文件系统权限继承检查
假设有一个多层级的文件目录结构,你想知道哪些文件夹中,所有子文件的权限都是一样的,这样就可以打包成一个统一模板。
- 节点 = 文件夹
- 节点值 = 权限值
- 子树同值判断 = 检查子目录权限一致
配置项一致性检查
比如你有一个配置树,里面可能有很多子配置。如果你想找到哪些配置项完全一致(便于缓存或者合并),这种“统一值的结构识别”就是这个题的思路。
时间复杂度
这题的时间复杂度是 O(n),因为每个节点最多访问一次。
空间复杂度取决于树的深度,最坏情况是 O(n),也就是退化成链状结构的时候。
测试用例简单跑一下:
let root = TreeNode(5)
root.left = TreeNode(1)
root.right = TreeNode(5)
root.left?.left = TreeNode(5)
root.left?.right = TreeNode(5)
root.right?.right = TreeNode(5)let solution = Solution()
print(solution.countUnivalSubtrees(root)) // 输出 4
最后的话
这题虽然在 LeetCode 上是 Easy 难度,但实际含金量挺高:你需要掌握“自底向上的遍历”、要会在递归中携带和判断状态、还要理解“结构是否满足条件”的整体判断。
如果你刷题是为了实战开发的思维训练,这种题一定不能只做一遍就忘了,建议把它变成一张图,标出每个节点是否是同值子树,再动手实现一遍。
相关文章:
Swift 解 LeetCode 250:搞懂同值子树,用递归写出权限系统检查器
文章目录 前言问题描述简单说:痛点分析:到底难在哪?1. 子树的概念搞不清楚2. 要不要“递归”?递归从哪开始?3. 怎么“边遍历边判断”?这套路不熟 后序遍历 全局计数器遍历过程解释一下:和实际场…...
怎样使用Python编写的Telegram聊天机器人
怎样使用Python编写的Telegram聊天机器人 代码直接运行可用 以下是对这段代码的详细解释: 1. 导入必要的库 import loggingfrom telegram import Update from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, filters, MessageHandler import log…...
Elixir语言的移动应用安全
Elixir语言的移动应用安全解析 引言 在当今的数字化时代,移动应用已经成为我们日常生活中不可或缺的一部分。从购物、社交到在线银行,几乎每一个生活领域都与移动应用紧密相连。然而,随着应用的普及,安全问题也随之而来。如何确…...
动态估算gas和gasPrice
目录 一、什么是动态估算? 二、动态估算 Gas(代码示例) ✅ 使用 Ethers.js 估算 gasLimit: 💡 发送交易时加一点 buffer: 三、动态估算 gasPrice / maxFee ✅ 获取当前 baseFee(用 provider): ✅ 搭配交易一起发送: 四、完整组合:动态估算 Gas + EIP-1559 费用…...
数据清洗
map阶段:按行读入内容,对内容进行检查,如果字段的个数少于等于11,就删除这条日志(不保留)去除日志中字段个数小于等于11的日志内容。 <偏移量,第一行的内容> → <通过刷选之后的第一行…...
增益调度控制 —— 理论、案例与交互式 GUI 实现
目录 增益调度控制 —— 理论、案例与交互式 GUI 实现一、引言二、增益调度控制的基本原理三、数学模型与公式推导四、增益调度控制的优势与局限4.1 优势4.2 局限五、典型案例分析5.1 案例一:航空飞行控制中的增益调度5.2 案例二:发动机推力控制中的增益调度5.3 案例三:化工…...
关于OEC/OEC-turbo刷机问题的一些解决方法(2)——可能是终极解决方法了
前面写了两篇关于OEC/OEC-turbo刷机问题的文章了,从刷机过程、刷机中遇到的问题,以及遇到最多但始终无法有效解决的下载boot失败的问题的剖析,最近确实也做了一些工作,虽然没有最终解决,但也算是这系列文章里面阶段性的…...
前后端接口参数详解与 Mock 配置指南【大模型总结】
前后端接口参数详解与 Mock 配置指南 一、前端请求参数类型及 Mock 处理 1.1 URL 路径参数 (Path Parameters) 场景示例: GET /api/users/{userId}/orders/{orderId}Mock.js 处理: Mock.mock(/\/api\/users\/(\d)\/orders\/(\d)/, get, (options) &g…...
瓦片数据合并方法
影像数据 假如有两份影像数据 1.全球底层影像0-5级别如下: 2.局部高清影像数据级别9-14如下: 合并方法 将9-14文件夹复制到全球底层0-5的目录下 如下: 然后合并xml文件 使得Tileset设置到最高级(包含所有级别)&…...
第16届蓝桥杯单片机模拟试题Ⅰ
试题 代码 sys.h #ifndef __SYS_H__ #define __SYS_H__#include <STC15F2K60S2.H> //onewire.c float getT(); //sys.c extern unsigned char UI; extern bit touch_mode; extern float jiaozhun; extern float canshu; extern float temper; void init74hc138(unsigned…...
mac 卸载流氓软件安全助手
之前个人电脑在公司使用过一段时间,为了使用网线联网安装了公司指定的 联软上网助手,谁知安装容易卸载难,后来找运维来卸载,输入管理员密码后,也无反应,最后不了了之了,这个毒瘤软件长期在后台驻…...
EM算法到底是什么东东
EM(Expectation-Maximization期望最大化)算法是机器学习中非常重要的一类算法,广泛应用于聚类、缺失数据建模、隐变量模型学习等场景,比如高斯混合模型(GMM)就是经典应用。 🐤 第一步ÿ…...
⭐算法OJ⭐滑动窗口最大值【双端队列(deque)】Sliding Window Maximum
文章目录 双端队列(deque)详解基本特性常用操作1. 构造和初始化2. 元素访问3. 修改操作4. 容量操作 性能特点时间复杂度:空间复杂度: 滑动窗口最大值题目描述方法思路解决代码 双端队列(deque)详解 双端队列(deque,全称double-ended queue)是…...
oracle 快速创建表结构
在 Oracle 中快速创建表结构(仅复制表结构,不复制数据)可以通过以下方法实现,适用于需要快速复制表定义或生成空表的场景 1. 使用 CREATE TABLE AS SELECT (CTAS) 方法 -- 复制源表的全部列和数据类型,但不复制数据 C…...
沧州铁狮子
又名“镇海吼”,是中国现存年代最久、形体最大的铸铁狮子,具有深厚的历史文化底蕴和独特的艺术价值。以下是关于沧州铁狮子的详细介绍: 历史背景 • 铸造年代:沧州铁狮子铸造于后周广顺三年(953年)&#…...
Python•判断循环
ʕ⸝⸝⸝˙Ⱉ˙ʔ ♡ 判断🍰常用的判断符号(比较运算符)andor括号notin 和 not inif-elif-else循环🍭计数循环 forrange()函数简易倒计时enumerate()函数zip()函数遍历列表遍历元组遍历字符串遍历字典条件循环 while提前跳转 continue跳出循环 break能量站😚判断🍰 …...
【力扣hot100题】(060)分割回文串
每次需要判断回文串,这点比之前几题回溯题目复杂一些。 还有我怎么又多写了循环…… class Solution { public:vector<vector<string>> result;string s;bool palindromic(string s){for(int i0;i<s.size()/2;i) if(s[i]!s[s.size()-1-i]) return …...
C++---day7
#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory>using namespace std;class Stu { private:public:};// 自定义 vector 类,重…...
SvelteKit 最新中文文档教程(17)—— 仅服务端模块和快照
前言 Svelte,一个语法简洁、入门容易,面向未来的前端框架。 从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1: Svelte …...
C#后端开发培训教程
C#后端开发培训教程 SqlServer 1.创建数据、备份还原数据库 2.SqlServer:数据类型 3.Sql语句:增删改查 4.班级、学生数据结构示例 C#基础语法 C#基础语法、数据类型 C#数组、集合、类操作 C#面向对象基础 C# JSON 数据格式序列化 C# Linq 数据源操作基础语…...
flink 增量快照同步文件引用关系和恢复分析
文章目录 文件引用分析相关代码分析从state 恢复,以rocksdb为例不修改并行度修改并行度keyGroupRange过程问题 文件引用分析 每次生成的checkpoint 里都会有所有文件的引用信息 问题,引用分析里如何把f1,f2去掉了,可以参考下面的代码&#…...
c++概念—内存管理
文章目录 c内存管理c/c的内存区域划分回顾c语言动态内存管理c动态内存管理new和delete的使用new和delete的底层逻辑operator new函数和operator delete函数new和delete的实现操作方式不匹配的情况定位new new/delete和malloc/free的区别 c内存管理 在以往学习c语言的过程中&…...
如何判断多个点组成的3维面不是平的,如果不是平的,如何拆分成多个平面
判断和拆分三维非平面为多个平面 要判断多个三维点组成的面是否为平面,以及如何将非平面拆分为多个平面,可以按照以下步骤进行: 判断是否为平面 平面方程法: 选择三个不共线的点计算平面方程:Ax By Cz D 0检查其…...
私有化视频会议系统,业务沟通协作安全不断线
BeeWorks Meet视频会议平台具备丰富而强大的功能,能够满足企业多样化的业务场景需求。其会议管理功能,让企业能够轻松安排和管理各类会议。 从创建会议、设置会议时间、邀请参会人员到会议提醒,一应俱全,确保会议的顺利进行。多人…...
无人机双频技术及底层应用分析!
一、双频技术的核心要点 1. 频段特性互补 2.4GHz:穿透力强、传输距离远(可达5公里以上),适合复杂环境(如城市、建筑物密集区),但易受Wi-Fi、蓝牙等设备的干扰。 5.8GHz:带宽更…...
【电视软件】小飞电视v2.7.0 TV版-清爽无广告秒换台【永久更新】
软件介绍 小飞电视是一款电视端的直播软件,无需二次付费和登录,资源丰富,高清流畅。具备开机自启、推送功能、自定义直播源、个性化设置及节目预告等实用功能,为用户带来良好的观看体验。基于mytv开源项目二改,涵盖央…...
video自动播放
文章目录 前言在iOS系统中,H5页面的自动播放功能受到了一些限制,为了提升用户体验和保护用户隐私,Safari浏览器对于自动播放的行为做了一些限制。 一、自动播放的限制二、解决方案 前言 在iOS系统中,H5页面的自动播放功能受到了一…...
以太网安全
前言: 端口隔离可实现同一VLAN内端口之间的隔离。用户只需要将端口加入到隔离组中,就可以实现隔离组内端口之间的二层数据的隔离端口安全是一种在交换机接入层实施的安全机制,旨在通过控制端口的MAC地址学习行为,确保仅授权设备能…...
Linux 递归查找并删除目录下的文件
在 Linux 中,可以使用 find 命令递归查找并删除目录下的文件 1、示例命令 find /path/to/directory -type f -name "filename_pattern" -exec rm -f {} 2、参数说明 /path/to/directory:要查找的目标目录type f:表示查找文件&am…...
Valgrind——内存调试和性能分析工具
文章目录 一、Valgrind 介绍二、Valgrind 功能和使用1. 主要功能2. 基本用法2.1 常用选项2.2 内存泄漏检测2.3 详细报告2.4 性能分析2.5 多线程错误检测 三、在 Ubuntu 上安装 Valgrind四、示例1. 检测内存泄漏2. 使用未初始化的内存3. 内存读写越界4. 综合错误 五、工具集1. M…...
