LeetCode 198:打家劫舍,从偷或不偷推出一维 DP

题目要求 输入输出 输入:整数数组 nums nums[i] 表示第 i 间房子的金额 不能偷相邻房子 输出:返回最多能偷到的金额 约束:1 <= nums.length <= 100,0 <= nums[i] <= 400 示例 输入:nums = [1,2,3,1] 输出:4 解释:偷下标 0 和下标 2,金额 1 + 3 = 4 输入:nums = [2,7,9,3,1] 输出:12 解释:偷下标 0、2、4,金额 2 + 9 + 1 = 12 这篇只用 Python,从这个二选一冲突推出一维 DP。 从 [1,2,3,1] 的相邻冲突开始 看例子: nums = [1,2,3,1] 如果偷下标 2 的房子,金额是 3,那么下标 1 和下标 3 都不能偷。 如果不偷下标 2,答案可能来自前面下标 0..1 的最优结果。 所以走到某一间房时,核心选择只有两个: ...

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

LeetCode 53:最大子数组和,从 dp[i] 含义推出 Kadane

题目要求 输入输出 输入:整数数组 nums 输出:返回连续非空子数组的最大和 子数组必须连续 至少选一个元素 约束:1 <= nums.length <= 10^5,-10^4 <= nums[i] <= 10^4 示例 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:[4,-1,2,1] 的和最大,为 6 输入:nums = [1] 输出:1 这篇只用 Python,从 dp[i] 的含义一步一步推出 Kadane 算法。 从 [-2,1,-3,4] 的断点开始 看一个前缀例子: nums = [-2, 1, -3, 4] 如果走到 4,有两种选择: 把前面的某个连续子数组接到 4 前面 从 4 自己重新开始 这里的关键不是“所有子数组怎么枚举”,而是: 当我们决定一个最优子数组必须以当前位置结尾时,它的来源只有两种:接上前一个位置的最优结尾,或者从当前位置重新开始。 这就是一维 DP 的入口。 Step 1:先定义一个更小的问题 直接问“整个数组的最大子数组和是多少”太大。我们先强加一个限制: 如果子数组必须以第 i 个元素结尾,它的最大和是多少? 这个值记为 dp[i]。 这里的 dp[i] 不是“前 i 个元素里的最大子数组和”。它更窄: ...

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

LeetCode 78:子集,从搜索树推出 startIndex 回溯模板

题目要求 输入输出 输入:nums,长度 1 <= nums.length <= 10 元素范围:-10 <= nums[i] <= 10 所有元素互不相同 输出:返回 nums 的所有可能子集 顺序:结果顺序不限,子集内部不需要考虑排列顺序 示例 输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] 这篇只用 Python 构造一个最小可运行解法。 从 [1,2] 的搜索树开始 最小但有分叉的例子是: nums = [1,2] 答案应该是: [], [1], [1,2], [2] 注意这里没有 [2,1]。这说明问题不是“随便排列所有选择”,而是“每个元素选或不选,且同一组元素只出现一次”。 如果把构造过程画成树: [] |- [1] | |- [1,2] |- [2] 这棵树暴露出两个事实: 每个节点都是一个合法子集。 进入 [1] 之后,后面只能继续看 2,不能回头再选 1 或生成 [2,1]。 Step 1:先说清楚一个递归层在解决什么 如果当前已经选出一个 path,剩下的问题是: 从某个起点之后的元素里,继续选择若干个元素,扩展当前 path。 这个“某个起点”必须被记下来。否则 [1,2] 和 [2,1] 会从不同路径重复出现。 先写最小骨架。它只保留两个状态: ...

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

LeetCode 90:子集 II,从重复分支推出层内去重

题目要求 输入输出 输入:nums,长度 1 <= nums.length <= 10 元素范围:-10 <= nums[i] <= 10 nums 可能有重复元素 输出:返回所有不重复子集 顺序:结果顺序不限,但同一个值序列的子集只能出现一次 示例 输入:nums = [1,2,2] 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]] 这篇只用 Python,从一个能跑但浪费的版本,一步一步过渡到排序 + 层内去重。 从 [1,2,2] 的重复分支开始 最小能暴露问题的例子是: nums = [1,2,2] 如果直接照搬 78. 子集 的模板,搜索树里会出现两条不同分支: 选择下标 1 的 2 -> [2] 选择下标 2 的 2 -> [2] 这两个分支路径不同,但值序列相同,最终答案重复。 所以这题真正新增的问题不是“会不会回溯”,而是: 怎样跳过重复分支,同时保留 [2,2] 这种合法答案? Step 1:先复用 78 的状态,看看哪里会坏 当前部分答案仍然需要 path;当前层仍然需要 start 控制只能往右选。 先写出 78 的核心版本: def dfs(start: int) -> None: res.append(path.copy()) for i in range(start, len(nums)): path.append(nums[i]) dfs(i + 1) path.pop() 这个版本在 nums 全部互不相同时是正确的。 ...

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

Hot100:从前序与中序遍历序列构造二叉树(Construct Binary Tree from Preorder and Inorder Traversal)索引分治 ACERS 解析

副标题 / 摘要 LeetCode 105 的关键不是死记“前序 + 中序能构树”,而是先看懂两种遍历各自提供什么信息。前序负责告诉你谁是根,中序负责告诉你左右边界,组合起来就能自然落成一个哈希定位的区间分治。 预计阅读时长:12~15 分钟 标签:Hot100、二叉树、分治、哈希表、前序遍历 SEO 关键词:Construct Binary Tree from Preorder and Inorder Traversal, 从前序与中序遍历序列构造二叉树, 前序遍历, 中序遍历, 分治, LeetCode 105 元描述:系统讲透 LeetCode 105 的构树推导、索引分治、哈希优化与多语言实现,并解释为什么一定要先建左子树。 A — Algorithm(题目与算法) 题目还原 给定一棵二叉树的前序遍历 preorder 和中序遍历 inorder,请你重建这棵二叉树并返回它的根节点。 题目保证: 树中元素没有重复 给出的两个数组一定来自同一棵合法二叉树 输入输出 名称 类型 描述 preorder int[] 前序遍历结果 inorder int[] 中序遍历结果 返回值 TreeNode 重建后的二叉树根节点 示例 1 输入:preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出:[3,9,20,null,null,15,7] 示例 2 输入:preorder = [-1], inorder = [-1] 输出:[-1] 提示 1 <= preorder.length <= 3000 inorder.length == preorder.length -3000 <= preorder[i], inorder[i] <= 3000 preorder 和 inorder 都没有重复元素 inorder 中的每个值都出现在 preorder 中 preorder 保证是某棵树的前序遍历 inorder 保证是同一棵树的中序遍历 目标读者 一看到“根据遍历结果构树”就会混淆前序和中序职责的学习者 想把“树的遍历顺序”和“树的结构恢复”建立稳定联系的开发者 做过 94、114 之后,想继续巩固树结构题的读者 背景 / 动机 这题最值得学的地方是: ...

2026年4月20日 · 9 分钟 · map[name:Jeanphilo]

Hot100:二叉树的右视图(Binary Tree Right Side View)层序遍历取每层最后一个 ACERS 解析

副标题 / 摘要 LeetCode 199 不是在考“看图想象力”,而是在考你能不能把视角问题翻译成层级问题。只要意识到右视图就是每一层最右边那个节点,这题就会立刻变成一个标准层序遍历。 预计阅读时长:10~13 分钟 标签:Hot100、二叉树、BFS、层序遍历、队列 SEO 关键词:Binary Tree Right Side View, 二叉树的右视图, 层序遍历, BFS, 右优先 DFS, LeetCode 199 元描述:系统讲透 LeetCode 199 的层序遍历解法,解释“右视图 = 每层最后一个节点”的本质,并补充右优先 DFS 视角。 A — Algorithm(题目与算法) 题目还原 给定一棵二叉树的根节点 root,想象你站在它的右侧,从上到下观察这棵树,返回你能看到的节点值。 输入输出 名称 类型 描述 root TreeNode 二叉树根节点 返回值 int[] 从上到下看到的右视图节点值 示例 1 输入:root = [1,2,3,null,5,null,4] 输出:[1,3,4] 示例 2 输入:root = [1,2,3,4,null,null,null,5] 输出:[1,3,4,5] 示例 3 输入:root = [1,null,3] 输出:[1,3] 示例 4 输入:root = [] 输出:[] 提示 二叉树的节点个数范围是 [0, 100] -100 <= Node.val <= 100 目标读者 已经会层序遍历,但不够熟悉“每层保留哪个节点”这类变形题的学习者 一看到“从某个方向看到的节点”就容易被题面叙述绕进去的开发者 想把 102 + 199 这一组 BFS 树题系统化的读者 背景 / 动机 这题很适合练习一个非常重要的动作: ...

2026年4月20日 · 8 分钟 · map[name:Jeanphilo]

Hot100:二叉树展开为链表(Flatten Binary Tree to Linked List)反向先序重连 ACERS 解析

副标题 / 摘要 LeetCode 114 的真正难点不是把树“拍平”,而是想清楚重连顺序。只要抓住“目标链表等于先序遍历顺序”,再把处理方向反过来,prev 指针会让整题变成一段非常稳定的原地递归。 预计阅读时长:12~15 分钟 标签:Hot100、二叉树、先序遍历、原地修改、递归 SEO 关键词:Flatten Binary Tree to Linked List, 二叉树展开为链表, 先序遍历, 原地修改, 反向先序, LeetCode 114 元描述:系统讲透 LeetCode 114 的反向先序重连思路,解释 prev 指针为什么有效,并补充工程迁移、复杂度与进阶 O(1) 方案。 A — Algorithm(题目与算法) 题目还原 给你一棵二叉树,请把它原地展开成一个“只沿 right 指针连接”的单链表。 展开后要满足两条规则: 每个节点的 left 都必须变成 null 沿 right 走出来的顺序,必须与原树的先序遍历顺序完全一致 输入输出 名称 类型 描述 root TreeNode 二叉树根节点 返回值 无 原地修改 root 示例 1 输入:root = [1,2,5,3,4,null,6] 输出:[1,null,2,null,3,null,4,null,5,null,6] 示例 2 输入:root = [] 输出:[] 示例 3 输入:root = [0] 输出:[0] 提示 树中结点数在范围 [0, 2000] 内 -100 <= Node.val <= 100 进阶 你可以使用原地算法(O(1) 额外空间)展开这棵树吗? ...

2026年4月20日 · 7 分钟 · map[name:Jeanphilo]

Hot100:二叉树中的最大路径和(Binary Tree Maximum Path Sum)树形 DP / 单边贡献 ACERS 解析

副标题 / 摘要 LeetCode 124 最容易混淆的地方是:递归到底该返回“整条最大路径”还是“能继续向上接的那一段贡献”。只要把这两个角色分开,这题就会变成一个非常典型的树形 DP。 预计阅读时长:12~15 分钟 标签:Hot100、二叉树、树形DP、DFS、后序遍历 SEO 关键词:Binary Tree Maximum Path Sum, 二叉树中的最大路径和, 树形DP, 单边贡献, 后序遍历, LeetCode 124 元描述:系统讲透 LeetCode 124 的单边贡献返回值、全局最大路径更新、负贡献剪枝与多语言实现。 A — Algorithm(题目与算法) 题目还原 二叉树中的一条路径定义为: 由若干个节点组成 相邻节点之间必须有边相连 同一个节点在一条路径里最多出现一次 路径至少包含一个节点 路径不一定经过根节点 路径和就是路径上所有节点值之和。 题目要求返回整棵树里的最大路径和。 输入输出 名称 类型 描述 root TreeNode 二叉树根节点 返回值 int 最大路径和 示例 1 输入:root = [1,2,3] 输出:6 解释:最优路径是 2 -> 1 -> 3,路径和为 6。 示例 2 输入:root = [-10,9,20,null,null,15,7] 输出:42 解释:最优路径是 15 -> 20 -> 7,路径和为 42。 提示 树中节点数目范围是 [1, 3 * 10^4] -1000 <= Node.val <= 1000 目标读者 已经做过 543,但还没完全理解“树上路径题”返回值该如何设计的学习者 一写最大路径和就会把“经过当前节点的完整路径”和“向上返回的贡献”混掉的开发者 想系统掌握树形 DP 基本套路的读者 背景 / 动机 这题的关键训练点是: ...

2026年4月20日 · 7 分钟 · map[name:Jeanphilo]

Hot100:二叉搜索树中第 K 小的元素(Kth Smallest Element in a BST)中序计数 / 提前停止 ACERS 解析

副标题 / 摘要 LeetCode 230 的难点不是“会中序遍历”,而是把 BST 的有序性用成真正有用的信息。只要抓住“中序第 k 次访问到的节点就是答案”,整题就会变成一个非常稳定的计数问题。 预计阅读时长:11~14 分钟 标签:Hot100、二叉树、BST、中序遍历、栈 SEO 关键词:Kth Smallest Element in a BST, 二叉搜索树中第 K 小的元素, BST, 中序遍历, 显式栈, LeetCode 230 元描述:系统讲透 LeetCode 230 的 BST 中序有序性、显式栈计数与提前停止技巧,并给出工程迁移与多语言实现。 A — Algorithm(题目与算法) 题目还原 给定一棵二叉搜索树 root 和一个整数 k,请找出这棵树中第 k 小的元素。 这里的 k 从 1 开始计数。 输入输出 名称 类型 描述 root TreeNode 二叉搜索树根节点 k int 第几个最小元素,1 <= k <= n 返回值 int 第 k 小的节点值 示例 1 输入:root = [3,1,4,null,2], k = 1 输出:1 示例 2 输入:root = [5,3,6,2,4,null,null,1], k = 3 输出:3 提示 树中的节点数为 n 1 <= k <= n <= 10^4 0 <= Node.val <= 10^4 进阶 如果 BST 经常插入、删除,并且需要频繁查询第 k 小,你会怎么优化? ...

2026年4月20日 · 8 分钟 · map[name:Jeanphilo]

Hot100:将有序数组转换为二叉搜索树(Convert Sorted Array to Binary Search Tree)分治选中点 ACERS 解析

副标题 / 摘要 LeetCode 108 的关键不在“会递归”,而在于看懂题目同时要求两件事:既要保持 BST 的有序性,又要尽量平衡。只要抓住“中点做根”这个证据,整题就会自然落成一个非常干净的区间分治。 预计阅读时长:11~14 分钟 标签:Hot100、二叉树、BST、分治、递归 SEO 关键词:Convert Sorted Array to Binary Search Tree, 将有序数组转换为二叉搜索树, 平衡二叉搜索树, BST, 分治, LeetCode 108 元描述:系统讲透 LeetCode 108 的中点分治构造法,覆盖题意推导、正确性解释、工程映射与多语言实现。 A — Algorithm(题目与算法) 题目还原 给你一个严格递增的整数数组 nums,请把它转换成一棵高度平衡的二叉搜索树。 这里同时包含两个目标: 新树必须满足 BST 的大小关系 新树还必须尽量平衡,也就是任意节点左右子树高度差不超过 1 输入输出 名称 类型 描述 nums int[] 严格递增数组 返回值 TreeNode 任意一棵合法的高度平衡 BST 根节点 示例 1 输入:nums = [-10,-3,0,5,9] 输出:[0,-3,9,-10,null,5] 解释:[0,-10,5,null,-3,null,9] 也同样正确。 示例 2 输入:nums = [1,3] 输出:[3,1] 解释:[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。 提示 1 <= nums.length <= 10^4 -10^4 <= nums[i] <= 10^4 nums 按严格递增顺序排列 目标读者 正在刷 Hot100,希望把“数组转树”的分治模板固定下来的学习者 已经会写 BST 判断,但还不够熟悉“BST 构造题”如何从题意推出来的开发者 想理解为什么“中点做根”不是技巧,而是由约束直接逼出来的读者 背景 / 动机 这题很适合拿来训练一个能力: ...

2026年4月20日 · 7 分钟 · map[name:Jeanphilo]