跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

二分查找经典例题实战解析

二分查找核心在于利用数据的二段性进行高效筛选。文章通过 LeetCode 经典例题,详解基础模板、左右边界定位、平方根计算及旋转数组等场景。重点讲解中点计算防溢出策略、循环终止条件细节,并提供 C++ 代码实现,助读者快速掌握算法精髓。

日志猎手发布于 2026/3/21更新于 2026/10/1786 浏览
二分查找经典例题实战解析

核心原理与模板

二分查找不仅仅是针对有序数组,其本质是利用数据的二段性。只要存在一个分界点能将数据分为满足条件和不满足条件两部分,就可以使用二分。

关键细节

  1. 循环终止条件 通常使用 left <= right。当 left == right 时仍需比较一次,确认该位置是否为目标值。若使用 left < right,则需根据具体场景调整边界更新逻辑。

  2. 中点计算防溢出 (left + right) / 2 在大多数情况下安全,但当两数之和超过整型最大值时会溢出。推荐写法:

    int mid = left + (right - left) / 2;
    

    这利用了起始值加偏移量的思路,既避免了溢出又保证了结果正确。

  3. 奇偶数处理 当区间长度为偶数时,中间有两个数。不加 1 取左中点,加 1 取右中点。选择哪种取决于更新逻辑(mid+1 还是 mid),目的是避免死循环。

经典例题实战

1. 基础查找 (LeetCode 704)

这是最朴素的二分模板。适用于严格单调递增序列。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, 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;
        }
        return -1;
    }
};

2. 查找元素的第一个和最后一个位置 (LeetCode 34)

此题需要分别查找左边界和右边界。由于目标值可能重复,找到相等值不能立即返回,需继续收缩区间。

查找左端点

  • 当 nums[mid] < target 时,左端点在右侧,left = mid + 1。
  • 当 nums[mid] >= target 时,左端点可能在 mid 处,right = mid。
  • 循环条件用 left < right,避免死循环。

查找右端点

  • 当 nums[mid] <= target 时,右端点可能在 mid 处,left = mid。
  • 当 nums[mid] > target 时,right = mid - 1。
  • 注意此时求中点需加 1:mid = left + (right - left + 1) / 2,防止 left=mid 导致死循环。
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if (nums.empty()) return {-1, -1};
        
        // 查找左端点
        int left = 0, right = nums.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) left = mid + 1;
            else right = mid;
        }
        
        // 检查是否存在
        if (nums[left] != target) return {-1, -1};
        
        // 查找右端点
        int l = 0, r = nums.size() - 1;
        while (l < r) {
            int m = l + (r - l + 1) / 2;
            if (nums[m] <= target) l = m;
            else r = m - 1;
        }
        
        return {left, r};
    }
};

3. x 的平方根 (LeetCode 69)

虽然题目未直接给出数组,但函数 $f(x) = x^2$ 具有单调性,可视为隐式数组。

需注意乘法溢出问题,建议使用 long long 类型存储中间结果。

class Solution {
public:
    int mySqrt(int x) {
        if (x < 1) return 0;
        int left = 1, right = x;
        while (left < right) {
            long long mid = left + (right - left + 1) / 2;
            if (mid * mid <= x) left = mid;
            else right = mid - 1;
        }
        return left;
    }
};

4. 搜索插入位置 (LeetCode 35)

寻找第一个大于等于目标值的位置。若所有元素都小于目标值,则返回末尾索引 +1。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) left = mid + 1;
            else right = mid;
        }
        if (target > nums[right]) return right + 1;
        return left;
    }
};

5. 山脉数组的峰顶索引 (LeetCode 852)

数组先增后减,虽非全局有序,但相对于峰值具有二段性。通过比较 mid 与相邻元素判断坡度方向。

这里采用 mid 与 mid-1 比较的策略:

  • 若 arr[mid] > arr[mid-1],说明处于上升段,峰值在右侧(含 mid),left = mid。
  • 否则处于下降段,right = mid - 1。
class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int left = 1, right = arr.size() - 2;
        while (left < right) {
            int mid = left + (right - left + 1) / 2;
            if (arr[mid] > arr[mid - 1]) left = mid;
            else right = mid - 1;
        }
        return left;
    }
};

6. 寻找旋转排序数组中的最小值 (LeetCode 153)

旋转数组由两段递增序列组成。以最后一个元素为基准进行划分:

  • 若 nums[mid] > nums[n],说明 mid 在第一段递增区,最小值在右侧,left = mid + 1。
  • 若 nums[mid] <= nums[n],说明 mid 在第二段,最小值在左侧(含 mid),right = mid。
class Solution {
public:
    int findMin(vector<int>& nums) {
        int n = nums.size() - 1;
        int left = 0, right = n;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] > nums[n]) left = mid + 1;
            else right = mid;
        }
        return nums[right];
    }
};

7. 点名问题 (LeetCode 173)

有序数组中缺失一个数字,利用索引与值的对应关系划分区间:

  • 若 records[mid] == mid,说明前半部分连续,缺失值在后半部分,left = mid + 1。
  • 否则缺失值在前半部分,right = mid。
class Solution {
public:
    int takeAttendance(vector<int>& records) {
        int left = 0, right = records.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (records[mid] == mid) left = mid + 1;
            else right = mid;
        }
        if (records[right] == right) return right + 1;
        return right;
    }
};

以上七类题型涵盖了二分查找的主要变体。掌握二段性的识别与边界条件的微调,是解决此类问题的关键。

目录

  1. 核心原理与模板
  2. 关键细节
  3. 经典例题实战
  4. 1. 基础查找 (LeetCode 704)
  5. 2. 查找元素的第一个和最后一个位置 (LeetCode 34)
  6. 3. x 的平方根 (LeetCode 69)
  7. 4. 搜索插入位置 (LeetCode 35)
  8. 5. 山脉数组的峰顶索引 (LeetCode 852)
  9. 6. 寻找旋转排序数组中的最小值 (LeetCode 153)
  10. 7. 点名问题 (LeetCode 173)

更多推荐文章

查看全部
  • 计算机视觉高级应用与前沿技术解析
  • 2026 前端跨端框架选型指南
  • Linux 底层核心精讲:环境变量、命令行参数与程序地址空间全解析
  • 微软 RAG 框架与 GraphRAG 技术深度解析
  • Pi0 机器人 VLA 大模型昇腾 A2 平台部署与测评
  • WebStorm 开发卡顿问题排查与性能优化方案
  • GESP 2023 年 12 月 C++ 二级认证试题解析(选择题 9-15)
  • Windows 本地部署 OpenClaw 接入飞书机器人
  • 前端 AJAX 原理与动态页面爬虫实战思路
  • 二分查找实战:旋转排序数组最小值与缺失数字求解
  • Lostlife2.0 整合 LLama-Factory 优化 NPC 对话逻辑
  • Java String 字符串核心特性与 API 详解
  • Linux 常用指令详解与重定向实战
  • WhisperLiveKit 会议纪要模板定制:适配不同场景样式
  • 星辰 RPA 构建小红书自动发文机器人
  • MIT 电机混合扭矩模式控制详解
  • 基于 FastGPT 与 MCP 协议构建工具增强型智能体
  • 2026 年主流智能编程工具对比与选型指南
  • 2026 年跨维度 AR 测试工具的技术演进与实战思考
  • 无需部署服务器:内网穿透实现本地服务对外演示

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online