【Hot 100】二分查找(单个目标值:查找目标值、多个目标值:查找目标值左右边界)

请添加图片描述

  • 🙋‍♂️ 作者:海码007
  • 📜 专栏:算法专栏
  • 💥 标题:【Hot 100】二分查找(单个目标值:查找目标值、多个目标值:查找目标值左右边界)
  • ❣️ 寄语:书到用时方恨少,事非经过不知难!

你说得对。你原文的风格确实更加自然、接地气,特别适合写在个人博客或者刷题笔记里。我的润色版本在表达上更偏向“技术文档”风格,确实失去了你原来的那种轻松、直白的语气。

那我们可以来一个**“轻度润色+保持原汁原味”**的版本,在不改你叙述节奏的基础上,把逻辑再捋顺一点、表达再清晰一点,同时保留你写作时的那种语感。下面是我调整后的版本:


引言

刷了很多道二分查找类型的题目后,今天来系统总结一下各种变形,尤其是边界处理的技巧

二分查找的题目类型

大致可以分为两类:

  1. 最多有一个目标值:比如「搜索插入位置」—— 要么找到目标值,要么返回它应该插入的位置(也就是第一个比它大的元素)。
  2. 可能有多个目标值:比如「查找目标值的左右边界」—— 找到一段连续的目标值的起始和结束位置。

单个目标值的标准二分查找

如果目标值最多只出现一次,那就可以直接用标准的二分模板来处理。常见的判断逻辑如下:

int left = 0;
int right = nums.size() - 1;

while (left <= right)
{
    int mid = left + (right - left) / 2;
    if (nums[mid] < target)
    {
        // 小于目标值,排除左半部分
        left = mid + 1;
    }
    else if (nums[mid] > target)
    {
        // 大于目标值,排除右半部分
        right = mid - 1;
    }
    else
    {
        // 找到了目标值
        return mid;
    }
}

那如果目标值不存在呢?

我们来观察一下最后循环结束时 leftright 的位置。

  • nums[mid] < target 时,我们移动 left = mid + 1,相当于把所有小于目标值的排除掉了。也就是说,left 会指向第一个大于等于目标值的位置
  • nums[mid] > target 时,我们移动 right = mid - 1,把所有大于目标值的排除掉了。也就是说,right 会指向最后一个小于等于目标值的位置

这就解释了为什么在 Leetcode 35 题「搜索插入位置」中,直接返回 left 就是目标值应该插入的位置。


多个目标值:查找左右边界

当目标值可能有多个时,就不能一看到等于目标值就直接返回了。比如下面这个数组:

nums = [1, 6, 6, 6, 6, 6, 9]
target = 6

如果我们用标准的二分查找,第一次碰到 nums[mid] == target 就返回,是无法得到目标值的左边界右边界的。


1. 查找左边界

要找到第一个等于目标值的位置,我们需要改一下条件:

  • 如果 nums[mid] < target,说明目标值在右边,移动左边界;
  • 如果 nums[mid] >= target,说明目标值可能在左边,也可能刚好是当前这个位置,先收缩右边界
int left = 0;
int right = nums.size() - 1;
while (left <= right)
{
    int mid = left + (right - left) / 2;
    if (nums[mid] < target)
        left = mid + 1;
    else
        right = mid - 1;
}
// 此时 left 指向的是第一个大于等于 target 的位置

2. 查找右边界

  • 如果 nums[mid] <= target,说明目标值还可能在右边,移动左边界;
  • 如果 nums[mid] > target,说明目标值只能在左边,收缩右边界。
int left = 0;
int right = nums.size() - 1;
while (left <= right)
{
    int mid = left + (right - left) / 2;
    if (nums[mid] <= target)
        left = mid + 1;
    else
        right = mid - 1;
}
// 此时 right 指向的是最后一个小于等于 target 的位置

特别注意:还得判断目标值到底存不存在

有时候数组里可能根本没有目标值,所以不能直接返回 leftright,而要先判断一下:

if (left == nums.size() || nums[left] != target)
    return {-1, -1}; // 没找到目标值

小结

这次做了很多二分查找的题目,最大的收获就是:控制判断条件,其实就是在控制最后 left 和 right 的位置。理解这一点之后,就能灵活地写出找左边界、右边界,甚至是插入位置的各种代码了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值