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

写二分查找时,我们经常先看到这样的初始化: 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 2529)

副标题 / 摘要 给定一个有序整数数组,如何在 O(log n) 时间内分别统计负数和正数的个数,并返回两者中的较大值?这道「Maximum Count of Positive & Negative Integers」正是边界型二分的练习题。本文用上下界二分一次性搞定负数结束和正数起点。 预计阅读时长:8~10 分钟 适用场景标签:二分查找、边界计数、排序数组 SEO 关键词:maximum count, positive negative, 二分统计, 上下界, 有序数组计数 目标读者与背景 目标读者 已经会写 basic binary search,希望进阶到“计数型二分”的同学; 在工程中有基于排序数据做区间计数需求的工程师; 准备面试,想把二分查找的上下界技巧练熟的开发者。 背景 / 动机 在各种日志 / 指标 / 数据分析场景中,我们经常会对有序数据做计数: 比如统计小于 0 的条目数量; 统计大于某个阈值的条目数量; 找到“负数段结束”和“正数段开始”的位置。 这道 LeetCode 题「Maximum Count of Positive & Negative Integers」是这类需求的简化模型,非常适合作为上下界二分的练习。 A — Algorithm(题目与算法) 题目重述 给定一个按非降序排序的整数数组 nums。 数组中可能包含负数、0 和正数。 定义: countNeg = 数组中小于 0 的元素数量; countPos = 数组中大于 0 的元素数量。 请返回 max(countNeg, countPos)。 输入 ...

2025年12月4日 · 8 分钟 · map[name:Jeanphilo]

比目标字母大的最小字母:有序字符数组上的二分查找技巧(LeetCode 744)

副标题 / 摘要 这道题看似只是“找一个比目标大的字母”,本质上是经典的上界二分(upper_bound)问题:在有序字符数组中找到第一个 > target 的元素,并在找不到时从头环绕。本文给出完整的二分模板和多语言实现,帮你稳拿这类边界题。 预计阅读时长:8~10 分钟 适用场景标签:二分查找进阶、字符数组、上界查找 SEO 关键词:find smallest letter greater than target, upper_bound, 二分查找字符数组 目标读者与背景 目标读者 已经掌握基本二分查找,想进一步熟悉上下界(upper/lower bound)的同学; 在工程中需要在有序集合中找到“下一个更大值”的开发者; 准备中高级面试,想通过一道题统一上界二分写法的工程师。 背景 / 动机 很多系统都会用到“环形有序列表”的概念: 比如按字母排序的标签、按时间排序的分片; 想要找“比当前值更大的下一个值”,找不到就从头开始。 这道题「Find Smallest Letter Greater Than Target」正是这种模式的简化版,是练习上界二分的好题。 A — Algorithm(题目与算法) 题目重述 给定一个按非降序排序的字符数组 letters,数组中的字母都是小写英文字母。 给定一个字符 target,请你找到数组中严格大于 target 的最小字母并返回。 注意:letters 数组是环绕的——如果不存在这样的字母,则返回数组的第一个元素。 输入 letters: 排序好的小写字母数组,长度为 n,且 letters 中至少有两个不同的字母; target: 一个小写字母。 输出 字符:数组中比 target 大的最小字母;若不存在,则为 letters[0]。 示例 1 letters = ['c', 'f', 'j'] target = 'a' 所有比 'a' 大的字母有 ['c', 'f', 'j']; 其中最小的是 'c'。 输出:'c' ...

2025年12月4日 · 6 分钟 · map[name:Jeanphilo]

经典 Binary Search:在排序数组中查找目标值索引的统一模板(LeetCode 704)

副标题 / 摘要 二分查找是所有算法面试和工程系统中的“必修课”。本文以最基础的「在有序数组中查找目标值」为例,从题意、边界到统一模板,系统整理 Binary Search 的写法,并配套多语言实现,帮助你彻底告别二分边界恐惧症。 预计阅读时长:8~10 分钟 适用场景标签:二分查找基础、数组检索、性能优化 SEO 关键词:binary search, LeetCode 704, 二分查找模板, 有序数组目标索引 目标读者与背景 目标读者 刚开始系统刷题、希望夯实基础二分查找的同学; 在工程中经常需要在有序列表中查找、定位数据的后端 / 前端工程师; 曾经被二分查找的边界条件困扰、希望形成统一模板的开发者。 为什么这题值得认真学? 它是 LeetCode 704:Binary Search,二分查找的最基础版本; 几乎所有高级二分题(Search Range、插入位置、求上下界)都以此为内核; 大量工程场景(有序列表查找、策略表、时间线等)都可以套用这个模板。 A — Algorithm(题目与算法) 题目重述 给定一个按非降序排序的整数数组 nums 和一个整数 target。 请你在数组中查找 target,如果存在,则返回其下标;否则,返回 -1。 要求算法的时间复杂度为 O(log n)。 输入 nums: 已排序(非降序)的整数数组,长度为 n target: 要查找的整数 输出 若 target 存在于 nums 中,则返回其下标; 否则返回 -1。 示例 1 nums = [-1, 0, 3, 5, 9, 12] target = 9 数组中存在 9,且在下标 4: ...

2025年12月4日 · 6 分钟 · map[name:Jeanphilo]

Hot100:Search Insert Position 排序数组中目标值插入位置的二分查找实战(LeetCode 35)

副标题 / 摘要 Search Insert Position 是二分查找的「Hello World」级题目:返回目标值在有序数组中的插入位置(存在返回下标,不存在返回应插入的下标)。本文用统一的 lower_bound 模板,把这个问题讲清楚,并展示其在日志、配置和策略表中的工程应用。 预计阅读时长:8~10 分钟 适用场景标签:二分查找入门、插入位置、范围查找 SEO 关键词:search insert position, lower_bound, 二分插入, 排序数组插入位置, LeetCode 35, Hot100 目标读者与背景 目标读者 知道二分查找基本原理,但还没形成自己的模板的同学; 在工程中经常对有序列表做插入 / 查找操作的后端 / 前端开发者; 刚开始刷 LeetCode,想用一道题把「下界二分」吃透的人。 为什么这题重要? 它是 most basic 的「lower_bound」模型: 第一个大于等于目标值的下标。 理解它之后: 起始位置 / 插入位置 / 统计 ≤ / ≥ 某值数量等,都可以统一用同一个模板。 在工程中: 策略阈值表、时间戳列表、版本列表等,都会用到类似逻辑。 A — Algorithm(题目与算法) 题目重述 给定一个按非降序排序的整数数组 nums 和一个目标值 target。 请在数组中搜索 target,如果存在则返回其下标; 如果不存在,则返回它按顺序插入时应该在的位置。 要求算法时间复杂度为 O(log n)。 输入 nums: 已排序(非降序)的整数数组,长度为 n target: 目标整数 输出 ...

2025年12月4日 · 6 分钟 · map[name:Jeanphilo]

LeetCode 34:在排序数组中查找元素的第一个和最后一个位置

题目要求 先看官方示例中的输入 nums = [5,7,7,8,8,10] 和 target = 8。答案必须是完整范围 [3,4];只返回下标 3 或 4,都没有回答目标值第一次和最后一次出现在哪里。 给定一个按非递减顺序排列的整数数组 nums 和一个整数 target: 如果 target 存在,返回它第一次和最后一次出现的下标 [first, last]。 如果 target 不存在,返回 [-1, -1]。 题目最终要求算法的运行时间为 O(log n)。 LeetCode 使用以下方法契约: class Solution: def searchRange(self, nums: List[int], target: int) -> List[int]: 官方示例 输入:nums = [5,7,7,8,8,10], target = 8 输出:[3,4] 输入:nums = [5,7,7,8,8,10], target = 6 输出:[-1,-1] 输入:nums = [], target = 0 输出:[-1,-1] 约束 0 <= nums.length <= 10^5 -10^9 <= nums[i] <= 10^9 -10^9 <= target <= 10^9 nums 按非递减顺序排列。 Step 1:先得到一个肯定正确的范围 当目标值连续出现多次时,怎样保证同时记录最早和最晚的下标? ...

2025年12月4日 · 7 分钟 · map[name:Jeanphilo]

咒语与药水的成功组合:排序 + 二分查找秒杀乘积约束问题(LeetCode 2300)

副标题 / 摘要 一道典型的“乘积 ≥ 阈值”计数题,看起来像是 O(n²) 的双重循环,实际上用「排序 + 二分查找」就能把复杂度压到 O((n+m)log m)。本文从题意抽象、核心公式到多语言实现,带你把这类阈值匹配问题彻底吃透。 预计阅读时长:10~15 分钟 适用场景标签:二分查找、排序计数、阈值匹配 SEO 关键词:spells and potions, successful pairs, 二分查找, lower_bound, 乘积约束 目标读者与背景 目标读者 已熟悉基本二分查找,想提升「在有序数组上做计数」能力的同学 后端 / 算法工程师,经常处理阈值判断与配对统计的问题 准备技术面试,希望积累“排序 + 二分”模板的开发者 为什么这题值得单独写一篇? 它把一个表面 O(n²) 的「所有配对」问题,转化成了对有序数组的二分计数; 公式非常典型:把 a * b ≥ success 转成 b ≥ ceil(success / a); 这种思路在推荐系统、风控额度、资源匹配等业务里屡见不鲜。 A — Algorithm(题目与算法) 题目重述 给定两个整数数组 spells 和 potions,以及一个正整数 success。 对于每个咒语 spells[i],我们定义它与药水 potions[j] 的组合是“成功”的,当且仅当: spells[i] * potions[j] >= success 请返回一个数组 ans,其中 ans[i] 表示第 i 个咒语可以与多少个药水形成成功组合。 ...

2025年12月4日 · 8 分钟 · map[name:Jeanphilo]