每日一题day2(Leetcode 704二分查找)


  1. 题目解析

该题"讲人话"就是:给定一个升序、无重复的整数数组nums和一个目标值target,找到target在数组中的下标;如果找不到,就返回-1。核心要求是必须用O(log n)的时间复杂度,不能用暴力遍历。

举个简单例子:nums = -1,0,3,5,9,12,target = 9,那么返回4(9在数组中的下标);如果target = 2,数组中没有,就返回-1。

题目难度:Easy(简单),核心考察:二分查找的核心思想、区间定义与边界处理,是算法入门的必刷题。


  1. 解法详解

本题有两种经典解法,均基于二分查找思想,核心差异在于"区间定义",从基础到进阶,新手可循序渐进理解~

解法1(闭区间 left, right,新手首选)

思路最直观:将搜索范围定义为闭区间left, right,每次计算中间位置mid,通过比较numsmid和target的大小,缩小搜索范围,直到找到目标或区间为空。

具体步骤:

  • 初始化left = 0(数组起始下标),right = nums.size() - 1(数组末尾下标),覆盖整个数组。

  • 循环条件:left ≤ right(闭区间中,left == right时仍有一个元素,需要检查)。

  • 计算mid:mid = left + (right - left) / 2(避免left+right溢出,等价于(left+right)/2)。

  • 比较判断:若numsmid == target,直接返回mid;若numsmid < target,目标在右半区间,left = mid + 1;若numsmid > target,目标在左半区间,right = mid - 1。

  • 循环结束后仍未找到,返回-1。

完整代码(C++,可直接提交):

cpp 复制代码
class Solution { 
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1; // 闭区间[left, right]初始化
        while (left <= right) { // 闭区间有效条件:left ≤ right
            // 计算mid,避免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; // 找到目标,返回下标
            }
        }
        return -1; // 区间为空,未找到目标
    } 
}; 
复制代码
复制代码
注意:这种写法是新手最容易掌握的,逻辑清晰,边界处理简单。核心是记住"闭区间"的规则:left和right都包含在搜索范围内,更新边界时要跳过mid(因为mid已判断不是目标)。

解法2(左闭右开区间 [left, right),进阶写法)

核心优化:将搜索范围定义为左闭右开区间[left, right),即left包含在区间内,right不包含。这种写法更贴合STL中lower_bound、upper_bound的底层实现,边界处理更统一。

核心思路:

- 初始化left = 0,right = nums.size()(右边界为数组长度,不包含最后一个元素)。

- 循环条件:left < right(左闭右开区间中,left == right时区间为空)。

- 计算mid的方式不变,边界更新差异:nums[mid] > target时,right = mid(因为right不包含,直接缩小到mid即可);其他情况和闭区间一致。

完整代码(C++,可直接提交):

```cpp
class Solution { 
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size(); // 左闭右开区间[left, right)初始化
        while (left < right) { // 左闭右开区间有效条件:left < right
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1; // 目标在右半区间,左边界右移
            } else if (nums[mid] > target) {
                right = mid; // 右边界不包含,直接设为mid
            } else {
                return mid; // 找到目标,返回下标
            }
        }
        return -1; // 区间为空,未找到目标
    } 
}; 
  1. 关键知识点总结
  • 二分查找核心:利用数组有序特性,每次将搜索范围减半,时间复杂度从暴力遍历的O(n)优化到O(log n),适用于有序、无重复的数组查找。

  • 区间定义是核心:两种写法的关键区别的是"right的初始化"和"循环条件",记住"闭区间含right,开区间不含right"即可。

  • 防溢出技巧:mid = left + (right - left) / 2 是必学技巧,避免left和right都接近int最大值时,left+right溢出。


  1. 常见错误思路提醒

很多新手刚学二分查找,容易踩3个坑,一定要注意:

  • 坑1:循环条件写错------闭区间用left <= right,若写成left < right,会漏掉left == right时的元素,导致漏查。

  • 坑2:mid计算溢出------直接写mid = (left + right) / 2,在大数组中会溢出,必须用left + (right - left) / 2。

  • 坑3:边界更新错误------闭区间中,numsmid > target时,误将right = mid - 1写成right = mid,会导致死循环;左闭右开区间中,误将right = mid写成right = mid - 1,会漏掉元素。


  1. 后续练习建议

二分查找是高频考点,基础题掌握后,可练习以下变种题,巩固区间思维:

  • LeetCode 35. 搜索插入位置(二分查找的延伸,找不到目标时返回插入位置)

  • LeetCode 153. 寻找旋转排序数组中的最小值(旋转数组的二分查找,进阶)

  • LeetCode 74. 搜索二维矩阵(二维有序数组的二分查找,拓展应用)


每日一题,坚持打卡,慢慢积累算法思维~ 有问题欢迎在评论区留言讨论!

相关推荐
Logic1013 小时前
C语言/数据结构位运算题解:异或XOR找出学习计划中的“独特学习时间“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
小蒋学算法4 小时前
算法-交替删除操作后最后剩下的整数-跟着灵茶山艾府学算法
数据结构·算法
荆棘鸟智能4 小时前
林业遥感长势评估怎么做?从NDVI时序分析到LiDAR蓄积量回归
人工智能·算法·智慧林业
hhb_6185 小时前
AIRAGDebug:一键定位RAG链路异常
人工智能·python·算法
朝朝辞暮i5 小时前
C++ 第 6 课:switch —— 多状态选择
开发语言·c++·算法
苏打豆6 小时前
Pinocchio源码阅读——刚体运动物理量空间变换及求导
c++·线性代数·算法·矩阵·机器人
FluxArt6 小时前
GPT Image 2.5 中文提示词教程:Flux Art 可复用模板
前端·gpt·算法
思麟呀6 小时前
位运算:从一个整数到一个集合
c语言·数据结构·c++·算法
阜阳山君GEO7 小时前
豆包 SEED 新版本 GEO 优化:信源金字塔、打分体系与避坑落地指南
人工智能·算法
晓天衡宇•评测社区7 小时前
晓天衡宇亮相 2026 云栖大会:迈向更可信的高质量评测
人工智能·算法·机器学习