LeetCode 155:最小栈,如何让最小值跟着栈一起变化

题目要求 设计一个栈 MinStack,支持以下操作: MinStack():初始化栈。 push(value):把 value 压入栈顶。 pop():删除栈顶元素。 top():返回栈顶元素。 getMin():返回栈中的最小元素。 题目要求每个操作的时间复杂度都是 O(1)。 pop、top 和 getMin 只会在栈非空时调用,因此不需要为这些方法设计额外的空栈返回值。 示例 输入操作: ["MinStack", "push", "push", "push", "getMin", "pop", "top", "getMin"] 输入参数: [[], [-2], [0], [-3], [], [], [], []] 输出: [null, null, null, null, -3, null, 0, -2] 对应的执行过程是: min_stack = MinStack() min_stack.push(-2) min_stack.push(0) min_stack.push(-3) min_stack.getMin() # -3 min_stack.pop() min_stack.top() # 0 min_stack.getMin() # -2 约束 -2^31 <= value <= 2^31 - 1 最多调用 3 * 10^4 次 push、pop、top 和 getMin pop、top 和 getMin 调用时栈一定非空 Step 1:弹出最小值后,前一个最小值从哪里回来 普通栈已经能保存值,并按照后进先出的顺序执行 push、pop 和 top。当前 baseline 是: ...

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

LeetCode 20:有效的括号,为什么数量相同仍然无效

题目要求 给定一个只包含以下六种字符的字符串 s: ( ) { } [ ] 判断这个字符串是否有效。有效字符串必须同时满足三个条件: 每个左括号都由相同类型的右括号闭合。 左括号必须按照正确顺序闭合。 每个右括号都有一个对应的同类型左括号。 满足全部条件时返回 True,否则返回 False。 示例 输入 输出 "()" True "()[]{}" True "(]" False "([])" True "([)]" False 约束 1 <= s.length <= 10^4 s 只包含 ()[]{} 中的字符 LeetCode 提供的方法签名是: class Solution: def isValid(self, s: str) -> bool: pass Step 1:数量相同为什么仍然无效 先看两个字符串: ()[]{} ([)] 它们都有一个 ( 和一个 )、一个 [ 和一个 ]。如果只分别统计三种左括号和右括号的数量,这两个字符串都会通过检查。 当前 baseline 是: 分别统计每种左括号和右括号;数量全部相同就认为字符串有效。 这个 baseline 会在 ([)] 上给出错误答案。问题不在括号数量,而在闭合顺序:读到一个右括号时,它必须闭合最近遇到、但还没有被闭合的左括号。 把这个规则用于 ([)]: ...

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

LeetCode 394:字符串解码,如何保存并恢复嵌套上下文

题目要求 给定一个编码字符串 s,返回它解码后的字符串。 编码规则是: k[encoded_string] 方括号中的 encoded_string 需要连续重复 k 次,其中 k 是正整数。编码可以嵌套,也可以与普通小写字母相邻。 题目保证: 输入字符串始终有效,方括号完整配对且没有多余空格。 原始文本不包含数字,数字只表示重复次数。 不会出现 3a 或 2[4] 这类不符合编码规则的输入。 解码后的字符串长度不会超过 10^5。 示例 输入 输出 "3[a]2[bc]" "aaabcbc" "3[a2[c]]" "accaccacc" "2[abc]3[cd]ef" "abcabccdcdcdef" 约束 1 <= s.length <= 30 s 只包含小写英文字母、数字和 [] 所有重复次数都在 [1, 300] 范围内 LeetCode 提供的方法签名是: class Solution: def decodeString(self, s: str) -> str: pass Step 1:进入内层以后,外层信息去了哪里 先从没有嵌套的输入开始: 3[a] 读到 3 后知道下一段需要重复三次;读完方括号中的 a,得到: a * 3 = aaa 当前 baseline 是: 读出一个重复次数,再收集后续方括号中的文本,遇到 ] 时执行重复。 这个 baseline 可以处理一层 3[a],却会在 3[a2[c]] 上中断。外层已经读到重复次数 3 和普通字母 a,此时又遇到了内层编码 2[c]。如果直接把当前次数改成 2、当前文本改成 c,外层的 3 和 a 就丢失了。 ...

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

二分查找区间怎么选:从候选集合到边界更新

写二分查找时,我们经常先看到这样的初始化: left = 0 right = len(nums) - 1 本文讨论的输入是按非递减顺序排列、允许重复值的 list[int]。精确查找要返回某个等于 target 的实际下标,不存在时返回 -1;左边界查找要返回 [0, n] 中第一个满足 nums[i] >= target 的位置,如果不存在这样的数组元素,就返回 n。 它看起来像是在声明一个闭区间,但只看这两行还不够。真正决定区间含义的是下面四件事是否一致: left 和 right 是候选下标、未分类边界,还是哨兵; 循环在什么条件下说明仍有实际元素需要检查; 检查 mid 后,更新是否正确排除了它; 循环结束时,哪个位置承载最终答案。 最可靠的判断方法不是背代码,而是先问一句: 当前哪些实际下标还没有被排除或分类,答案位置又被限制在哪个范围内? 这些持续成立的事实就是二分查找的循环不变式。区间符号、初始化和更新规则都应该从它推出来。 闭区间 [left, right] 当 left 和 right 都指向尚未排除的实际数组下标时,候选集合是闭区间: left = 0 right = len(nums) - 1 此时两个端点都可能是答案,所以只要 left <= right,区间就仍然非空: while left <= right: 如果 mid 不是答案,下一轮必须把它排除: if nums[mid] < target: left = mid + 1 else: right = mid - 1 因此,这套约定是: 项目 规则 候选集合 [left, right] 初始化 left = 0, right = n - 1 非空条件 left <= right 排除 mid left = mid + 1 或 right = mid - 1 空区间 left > right 它很适合“找到任意一个等于 target 的位置”:命中时直接返回,区间为空时返回不存在。 ...

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

LeetCode 74:搜索二维矩阵

给你一个 m x n 的整数矩阵 matrix 和一个整数 target。如果 target 在矩阵中,返回 True;否则返回 False。 题目给出的矩阵满足两个条件: 每一行都按非递减顺序排列。 每一行的第一个整数都严格大于上一行的最后一个整数。 要求算法的时间复杂度为 O(log(m * n))。 例如,对于下面的矩阵: 1 3 5 7 10 11 16 20 23 30 34 60 target = 3 时返回 True。 target = 13 时返回 False。 约束如下: 1 <= m, n <= 100 -10^4 <= matrix[i][j], target <= 10^4 LeetCode 提供的方法签名是: class Solution: def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: pass 第一步:扫描每一个元素 现在只有题目条件和方法签名,还没有一段能判断目标值是否存在的代码。先解决最基本的问题:怎样得到一个可以直接运行、结果确定正确的版本? 当前基线无法对示例中的 3 或 13 给出答案。加入一层遍历每一行的循环,再在当前行中检查每一个值。遇到目标值就立即返回 True;只有检查完所有元素仍未命中时,才返回 False。 ...

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

LeetCode 153:寻找旋转排序数组中的最小值

题目要求 输入给出一个非空整数数组 nums。数组中的元素互不相同;旋转前,数组按严格递增顺序排列。 数组会被旋转 1 到 nums.length 次。每旋转一次,就把最后一个元素移到数组最前面;因此,旋转 nums.length 次后,数组恢复为原来的递增顺序。返回旋转后数组中的最小值。题目要求算法的运行时间为 O(log n)。 LeetCode 使用以下方法契约: class Solution: def findMin(self, nums: List[int]) -> int: 官方示例 输入:nums = [3,4,5,1,2] 输出:1 输入:nums = [4,5,6,7,0,1,2] 输出:0 输入:nums = [11,13,15,17] 输出:11 约束 1 <= nums.length <= 5000 -5000 <= nums[i] <= 5000 nums 中的所有整数互不相同。 旋转前,nums 按严格递增顺序排列。 nums 被旋转 1 到 nums.length 次。 Step 1:先得到一个肯定正确的最小值 对于 [3,4,5,1,2],为什么不能直接返回第一个元素? 压力 这个数组的第一个元素是 3,但最小值是旋转后移到中间的 1。旋转保留了所有值,却不保证最小值仍在下标 0,所以直接返回 nums[0] 会得到错误答案。 ...

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

LeetCode 33:搜索旋转排序数组

题目要求 输入给出一个整数数组 nums 和一个整数 target。nums 中的元素互不相同;旋转前,数组严格递增。调用方法前,数组可能在某个未知下标 k(0 <= k < nums.length)处旋转为: [nums[k], ..., nums[n-1], nums[0], ..., nums[k-1]] 如果 target 存在,返回它在旋转后数组中的下标;否则返回 -1。题目要求算法的运行时间为 O(log n)。 LeetCode 使用以下方法契约: class Solution: def search(self, nums: List[int], target: int) -> int: 官方示例 输入:nums = [4,5,6,7,0,1,2], target = 0 输出:4 输入:nums = [4,5,6,7,0,1,2], target = 3 输出:-1 输入:nums = [1], target = 0 输出:-1 约束 1 <= nums.length <= 5000 -10^4 <= nums[i], target <= 10^4 nums 中的每个值都互不相同。 nums 旋转前按严格递增顺序排列。 Step 1:先正确搜索每一种旋转 对于 [4,5,6,7,0,1,2],怎样先得到一个不受旋转位置影响的正确答案? ...

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

LeetCode 503:下一个更大元素 II,循环数组中的右侧到哪里结束

题目要求 给定一个循环整数数组 nums,返回数组 answer。 对每个下标 i: answer[i] = 从 i 向右遇到的第一个严格大于 nums[i] 的元素值 如果绕行一圈后仍然没有更大元素,answer[i] = -1。 “循环数组”表示走过最后一个位置后,可以继续从下标 0 开始;但一个下标不能绕一圈后把自己当成答案。 LeetCode 提供的方法接口是: nextGreaterElements(nums: List[int]) -> List[int] 示例 1 输入:nums = [1,2,1] 输出:[2,-1,2] 第一个 1 向右首先遇到更大的 2。 2 绕行一圈也找不到严格更大的元素,答案是 -1。 最后一个 1 走到数组末尾后绕回开头,随后遇到 2。 示例 2 输入:nums = [2,2,2] 输出:[-1,-1,-1] 相等元素不属于“更大元素”。 示例 3 输入:nums = [7] 输出:[-1] 数组只有一个元素时,它不能把自己作为下一个更大元素。 约束 1 <= nums.length <= 10^4 -10^9 <= nums[i] <= 10^9 Step 1:循环数组中的“右边”到哪里结束 先看: ...

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

LeetCode 84:柱状图中最大的矩形,连续区间的高度由谁决定

题目要求 给定一个非负整数数组 heights。每个 heights[i] 表示宽度为 1 的柱子高度,所有柱子紧挨排列。 题目要求返回柱状图中能够形成的最大矩形面积。 一个合法矩形必须覆盖一段连续柱子。它的宽度是这段区间包含的柱子数量,高度不能超过区间中的最矮柱。 LeetCode 提供的方法接口是: largestRectangleArea(heights: List[int]) -> int 示例 1 输入:heights = [2,1,5,6,2,3] 输出:10 下标 2 和 3 的两根柱子高度分别是 5 和 6,可以形成高度 5、宽度 2、面积 10 的矩形。 示例 2 输入:heights = [2,4] 输出:4 可以选择高度 4、宽度 1,也可以选择高度 2、宽度 2,最大面积都是 4。 约束 1 <= heights.length <= 10^5 0 <= heights[i] <= 10^4 Step 1:矩形面积不是柱高之和 先看一个小柱状图: heights = [2,1,2] 如果矩形覆盖全部三根柱子,它的宽度是 3,但高度最多只能是 1: height = 1 width = 3 area = 1 * 3 = 3 不能把三根柱高相加得到 5。柱状图矩形覆盖的是一块完整矩形区域,中间高度为 1 的柱子会限制整个区间的矩形高度。 ...

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

LeetCode 136:只出现一次的数字,如何在常量空间排除重复元素

题目要求 给你一个非空整数数组 nums。 数组中只有一个元素出现一次,其余每个元素都恰好出现两次。题目要求返回那个只出现一次的元素。 LeetCode 提供的方法接口是: singleNumber(nums: List[int]) -> int 除了返回正确答案,解法还需要满足两个要求: 时间复杂度是 O(n)。 只使用 O(1) 额外空间。 示例 1 输入:nums = [2,2,1] 输出:1 2 出现两次,只有 1 出现一次。 示例 2 输入:nums = [4,1,2,1,2] 输出:4 1 和 2 都能找到相同的另一个元素,最后只有 4 没有配对。 示例 3 输入:nums = [1] 输出:1 数组只有一个元素时,它就是答案。 约束 1 <= nums.length <= 3 * 10^4 -3 * 10^4 <= nums[i] <= 3 * 10^4 除一个元素只出现一次外,其余元素都恰好出现两次。 Step 1:先把“只出现一次”说准确 先看: nums = [4,1,2,1,2] 在这个很小的数组里,我们可以用眼睛寻找相同的数字: ...

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