Hot100:对称二叉树(Symmetric Tree)镜像递归 / BFS ACERS 解析

副标题 / 摘要 对称二叉树的难点不在遍历,而在“比较方向”。你比较的不是左对左、右对右,而是镜像位置上的节点对。本文按 ACERS 结构拆解 LeetCode 101 的镜像递归合同、BFS 成对入队写法,以及工程中的对称结构校验场景。 预计阅读时长:10~12 分钟 标签:Hot100、二叉树、DFS、BFS、对称性 SEO 关键词:Hot100, Symmetric Tree, 对称二叉树, 镜像递归, BFS, LeetCode 101 元描述:系统讲透 LeetCode 101 的镜像递归与 BFS 对称校验思路,并延伸到布局树与拓扑模板的对称检查。 目标读者 刚从 100 相同的树过渡到“镜像比较”的刷题读者 会写普通树递归,但对“外侧 / 内侧”比较关系容易写乱的开发者 需要在布局树、模板树、镜像结构里做左右对称校验的工程师 背景 / 动机 LeetCode 101 很适合作为树题里的“方向感”训练: 你要先意识到,对称不是“左右子树完全一样” 它要求的是“左边看过去”和“右边镜像过来”之后一致 也就是说,比较方向从“同向”变成了“交叉” 很多人做这题时容易犯三类错误: 还沿用 100 的思路,写成 left.left 对 right.left 只比较节点值,不比较空节点位置 先翻转一棵子树再比较,结果多做了一轮变换,逻辑也更绕 这题真正训练的是“镜像递归模板”。掌握后,树对称、树镜像、结构匹配等题都会更清楚。 核心概念 镜像关系:左子树的左边,要和右子树的右边对应;左子树的右边,要和右子树的左边对应 外侧 / 内侧配对:left.left 对 right.right,left.right 对 right.left 成对递归:递归函数参数是两个节点,表示“这两个位置是否互为镜像” 成对入队:BFS 里队列保存的不是单个节点,而是需要一起比较的节点对 A — Algorithm(题目与算法) 题目还原 给你一个二叉树的根节点 root,检查它是否轴对称。 ...

2026年3月15日 · 7 分钟 · map[name:Jeanphilo]

相同的树(Same Tree)同步递归 / BFS ACERS 解析

副标题 / 摘要 LeetCode 100 的关键不在“会不会遍历树”,而在“能不能把两棵树当成一对一对的节点同步比较”。本文按 ACERS 结构拆解同步递归的判断合同、BFS 成对校验写法,以及工程里常见的结构等价判断场景。 预计阅读时长:9~11 分钟 标签:二叉树、DFS、BFS、树比较 SEO 关键词:Same Tree, 相同的树, 二叉树比较, 同步递归, LeetCode 100 元描述:系统讲透 LeetCode 100 的同步递归与 BFS 成对比较思路,并延伸到配置树、组件树和语法树的等价判断。 目标读者 刚开始刷树题,想建立“成对递归”思维的读者 能写单棵树 DFS,但一涉及“两棵树同时比较”就容易混乱的开发者 需要在配置树、组件树、语法树里判断结构是否一致的工程师 背景 / 动机 很多人第一次做 100,会本能地把问题理解成“分别遍历两棵树,再比较结果”。 这当然能做,但它绕远了。题目真正考的是: 你能不能把 p 和 q 上的对应节点同时拿出来看 你能不能把“相同”的定义拆成一套稳定的判断合同 你能不能在递归里先处理空节点,再处理值和子树 这类思维在后续很多树题里都会反复出现,比如: 判断一棵树是否是另一棵树的子树 判断左右子树是否镜像对称 校验两份树形配置是否结构等价 所以 100 虽然简单,但它是“双树同步递归模板”的起点。 核心概念 同步递归:递归函数参数不是一个节点,而是一对节点 p 和 q 结构相同:对应位置都存在节点,且左右子树结构也一致 值相同:对应位置的节点值相等 成对遍历:无论 DFS 还是 BFS,核心都是“每次处理一对节点” A — Algorithm(题目与算法) 题目还原 给你两棵二叉树的根节点 p 和 q,编写一个函数来检验这两棵树是否相同。 ...

2026年3月15日 · 6 分钟 · map[name:Jeanphilo]

Hot100:翻转二叉树(Invert Binary Tree)递归 / BFS ACERS 解析

副标题 / 摘要 翻转二叉树是一道看起来非常短、却能快速检验你是否真正理解递归结构的题。本文围绕 LeetCode 226 拆解“交换左右子树”的本质,给出递归 / BFS 两种做法,以及结构镜像在工程中的迁移思路。 预计阅读时长:8~10 分钟 标签:Hot100、二叉树、递归、BFS、树变换 SEO 关键词:Hot100, Invert Binary Tree, 翻转二叉树, 树镜像, 递归, LeetCode 226 元描述:讲清 LeetCode 226 的递归与 BFS 解法,并延伸到布局镜像、结构变换等工程场景。 目标读者 想检验自己是否真正理解“递归作用在整棵树每个节点上”的刷题读者 看到树题就下意识写遍历,但不确定该在什么时机处理当前节点的开发者 需要做树形结构镜像、布局翻转或对称转换的工程师 背景 / 动机 226 的代码通常很短,但它的思维非常典型: 当前节点要做什么? 把 left 和 right 交换。 子问题是什么? 左右子树本身也都要继续翻转。 这就是非常纯粹的“当前操作 + 递归处理子问题”。 如果你对这题没有完全吃透,往往会出现: 只交换根节点,不继续处理子树 交换后递归方向写乱 把本来能原地完成的事,额外重建一棵新树 核心概念 树镜像(mirror):把每个节点的左子树与右子树对调 原地变换(in-place transform):不新建整棵树,只交换指针 递归分治:当前节点处理完后,左右子树仍是同类型问题 BFS 层序变换:也可以按层把每个节点的左右孩子交换 A — Algorithm(题目与算法) 题目还原 给你一棵二叉树的根节点 root,请将这棵树翻转,并返回翻转后的根节点。 输入输出 名称 类型 描述 root TreeNode 二叉树根节点,可以为空 返回值 TreeNode 翻转后的根节点 示例 1 输入: root = [4,2,7,1,3,6,9] 输出: [4,7,2,9,6,3,1] 解释: 原树左右子树整体对调后,所有节点都完成镜像翻转。 示例 2 输入: root = [2,1,3] 输出: [2,3,1] 示例 3 输入: root = [] 输出: [] 约束 树中节点数目在 [0, 100] 内 -100 <= Node.val <= 100 C — Concepts(核心思想) 思路推导:为什么“交换 + 递归”就够了 假设当前节点是 node,我们要做的事情只有两步: ...

2026年3月6日 · 6 分钟 · map[name:Jeanphilo]

Hot100:二叉树的最大深度(Maximum Depth of Binary Tree)DFS / BFS ACERS 解析

副标题 / 摘要 “最大深度”是树递归最标准的起手式。你只要真正理解“当前树的答案依赖左右子树答案”的定义,整类树形 DP / DFS 题都会顺很多。本文以 LeetCode 104 为核心,系统讲解递归 DFS、层序 BFS 与工程迁移方法。 预计阅读时长:9~11 分钟 标签:Hot100、二叉树、DFS、BFS、递归 SEO 关键词:Hot100, Maximum Depth of Binary Tree, 二叉树的最大深度, DFS, BFS, LeetCode 104 元描述:从深度定义出发,讲清 LeetCode 104 的 DFS 和 BFS 解法,并附多语言可运行代码。 目标读者 刚开始刷树题,想把“树递归返回值”真正吃透的同学 能写遍历,但一遇到“求高度 / 求路径 / 求答案”就容易混乱的开发者 需要在菜单树、组织架构、嵌套 JSON 等层级数据里做深度分析的工程师 背景 / 动机 LeetCode 104 看起来像一道“送分题”,但它几乎是所有树递归的母题: 你需要先回答“空树深度是多少” 再回答“当前节点的答案依赖谁” 最后把关系写成 1 + max(left, right) 一旦这个递归定义真正建立起来,后续的平衡二叉树、直径、路径和、最近公共祖先都会更容易进入状态。 核心概念 深度 / 高度:这里按题意,根到最远叶子节点的节点数 后序式思维:想知道当前节点答案,必须先知道左右子树答案 DFS:递归向下,回溯时组合答案 BFS:按层遍历,最后一层编号就是树深度 A — Algorithm(题目与算法) 题目还原 给定二叉树根节点 root,返回其 最大深度。 ...

2026年3月6日 · 5 分钟 · map[name:Jeanphilo]

Hot100:二叉树的中序遍历(Binary Tree Inorder Traversal)递归 / 显式栈 ACERS 解析

副标题 / 摘要 二叉树遍历是树题模板的起点,中序遍历则是“递归思维”和“显式栈模拟”最典型的一题。本文按 ACERS 结构拆解 LeetCode 94,把左-根-右的访问顺序、迭代栈写法和工程迁移价值一次讲清。 预计阅读时长:10~12 分钟 标签:Hot100、二叉树、DFS、栈、中序遍历 SEO 关键词:Hot100, Binary Tree Inorder Traversal, 二叉树的中序遍历, 中序遍历, 显式栈, LeetCode 94 元描述:从递归到显式栈,系统讲透 LeetCode 94 二叉树中序遍历,并给出工程场景迁移与多语言实现。 目标读者 正在刷 Hot100,希望把树遍历模板固定下来的同学 刚从数组 / 链表过渡到树结构,容易把前序、中序、后序顺序写混的开发者 需要在 BST、表达式树、抽象语法树里复用“左-根-右”思想的工程师 背景 / 动机 中序遍历本身不复杂,但它的训练价值很高: 它是“递归 = 隐式栈,迭代 = 显式栈”最容易建立直觉的一题 它能帮助你稳定掌握“先一路向左,再回退访问根,再转向右子树”的过程 在 二叉搜索树(BST) 里,中序遍历天然得到有序序列,工程迁移价值很强 很多人第一次写树题不是逻辑不会,而是: 不清楚访问顺序到底是谁先谁后 迭代版不知道什么时候入栈、什么时候出栈 一旦树为空或只有单边链,代码就容易写乱 这题把模板练熟,后面的验证 BST、找第 k 小元素、恢复二叉搜索树等题会更顺。 核心概念 中序遍历:按照 左子树 -> 根节点 -> 右子树 的顺序访问 DFS(深度优先搜索):树遍历最常见的组织方式,中序遍历就是 DFS 的一种访问顺序 显式栈:把递归调用栈手动写出来,用栈保存“回头还要处理的节点” 树高 h:空间复杂度通常写成 O(h),平衡树约为 O(log n),极端退化链表时是 O(n) A — Algorithm(题目与算法) 题目还原 给定二叉树根节点 root,返回它的 中序遍历 结果。 ...

2026年3月6日 · 6 分钟 · map[name:Jeanphilo]

先等价迁移,再行为改造:AI 协作时代最稳的工程工作流

把复杂改造拆成“对齐基线”和“设计优化”两波,控制变量、提升可回滚性与排障效率。

2026年3月5日 · 2 分钟 · map[name:Jeanphilo]

手写一个基础消息代理:发布、订阅、重试与失败契约

用一个可运行的 Go 版本基础消息代理,讲透发布订阅、重试语义、失败契约、吞吐与积压估算,以及从朴素实现到工程可用实现的关键取舍。

2026年2月28日 · 8 分钟 · map[name:Jeanphilo]

Git Worktree 使用教程:同仓库并行开发多个分支

标题 Git Worktree 使用教程:同仓库并行开发多个分支 副标题 / 摘要 git worktree 让你在同一个 Git 仓库下,同时打开多个分支对应的工作目录,不用来回 checkout 和 stash。 本文覆盖常用命令、典型场景、常见坑,以及你最关心的 hotfix 分支创建方式(先进入 worktree 再建分支 / 一步建分支)。 目标读者 正在同时处理多个需求分支(feature / bugfix / hotfix)的开发者 经常需要切到 main 修紧急问题,但不想污染当前工作目录的人 需要对比不同分支代码、并行运行不同版本服务的工程师 背景 / 动机 很多人第一次遇到并行任务时,会用这套流程: git stash git checkout main # 修 bug git checkout feature/xxx git stash pop 这套流程不是不能用,但有几个问题: stash 容易忘记清理或弹错时机 来回切分支容易打断当前开发节奏 长时间运行测试/构建会占住当前工作目录 对比两个分支代码时不够直观 git worktree 的价值就是:在一个仓库里同时拥有多个工作目录,各做各的事,互不干扰。 核心概念 worktree(工作树):同一仓库的一个额外工作目录 共享对象库:多个 worktree 共享同一套 Git 对象数据(不是多个独立 clone) 独立工作目录:每个 worktree 有自己的文件内容、当前分支、未提交修改 分支占用限制:同一分支不能同时被多个 worktree 检出(Git 会保护你) stash 是仓库级别:不是 worktree 级别,多个 worktree 共享同一个 stash 列表 结构示意(ASCII): ...

2026年2月25日 · 4 分钟 · map[name:Jeanphilo]

Docker 常用使用教程:从入门到 Compose 实战(含 save/load 与权限排障)

标题 Docker 常用使用教程:从入门到 Compose 实战(含 save/load 与权限排障) 副标题 / 摘要 很多人会 docker run,但一到离线交付和挂载权限就卡住。 本文按“能直接落地”的顺序,带你走完 Docker 常用命令、Dockerfile、Compose、save/load,以及最常见的 UID/GID 权限问题。 目标读者 想系统掌握 Docker 日常用法的开发者 需要用 Docker Compose 跑本地或测试环境的工程师 经常遇到“挂载目录写不进去”权限问题的人 背景 / 动机 在“我的机器能跑、你的机器跑不起来”的场景里,Docker 的价值不是概念,而是交付稳定性。 但实际使用中,常见断点通常在三处: 命令会用,但不知道整套流程怎么串起来 需要离线迁移时,不清楚 save/load 怎么和 Compose 配合 挂载宿主目录后,容器用户与宿主目录属主不一致导致 Permission denied 核心概念 镜像(Image):应用运行模板,分层存储,可复用 容器(Container):镜像的运行实例 仓库(Registry):镜像分发中心(如 Docker Hub) 卷(Volume):由 Docker 管理的数据持久化目录 Bind Mount:把宿主机目录直接挂载进容器 Compose:用一个 compose.yaml 管理多容器应用 一、安装与最小验证 先确保 Docker CLI 与 daemon 可用: docker --version docker info docker run --rm hello-world 如果 hello-world 能成功输出欢迎信息,说明基础环境已就绪。 ...

2026年2月12日 · 3 分钟 · map[name:Jeanphilo]

LeetCode 146:LRU 缓存设计(O(1))哈希表 + 双向链表实战

副标题 / 摘要 这题不是“背答案题”,而是缓存系统的基本功:如何在常数时间内同时满足“快速访问”和“按最近最少使用淘汰”。本文从朴素方案推到最优结构,并给出可运行的多语言实现。 预计阅读时长:14~18 分钟 标签:LRU、哈希表、双向链表、系统设计 SEO 关键词:LRU Cache, LeetCode 146, 哈希表, 双向链表, O(1) 元描述:通过哈希表 + 双向链表实现 LRU 缓存,get/put 平均 O(1),附工程场景、常见坑与六语言实现。 A — Algorithm(题目与算法) 题目重述 设计并实现一个满足 LRU 约束的数据结构 LRUCache: LRUCache(int capacity):用正整数容量初始化 int get(int key):若 key 存在返回 value,否则返回 -1 void put(int key, int value): key 已存在:更新 value,并视作最近使用 key 不存在:插入新键值对 若超出容量:淘汰最久未使用的 key 并要求 get 和 put 平均时间复杂度为 O(1)。 示例 1(操作序列) LRUCache cache = new LRUCache(2) cache.put(1, 1) // 缓存: {1=1} cache.put(2, 2) // 缓存: {1=1, 2=2} cache.get(1) // 返回 1,且 1 变成最近使用 cache.put(3, 3) // 容量满,淘汰 key=2 cache.get(2) // 返回 -1 cache.put(4, 4) // 淘汰 key=1 cache.get(1) // 返回 -1 cache.get(3) // 返回 3 cache.get(4) // 返回 4 示例 2(更新已有键) LRUCache cache = new LRUCache(2) cache.put(1, 10) cache.put(1, 99) // 更新 value,且 1 视作最近使用 cache.get(1) // 返回 99 目标读者 正在刷 LeetCode 中等题、想吃透“数据结构组合技”的同学 做后端/中间件,需要实现或优化本地缓存的工程师 面试中经常被问到 LRU,但只记住结论、没掌握细节的人 背景 / 动机 缓存是“空间换时间”,但空间是有限的。 当缓存满了,必须淘汰一些键。LRU(Least Recently Used,最近最少使用)假设: ...

2026年2月11日 · 13 分钟 · map[name:Jeanphilo]