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

二分算法:8 道经典题目详解与实战

通过 8 道经典算法题详细讲解二分查找算法的应用。涵盖标准查找、查找范围、平方根、插入位置、山脉数组峰顶、寻找峰值、旋转数组最小值及缺失数字问题。每道题均提供解题思路、步骤分析及 C++ 代码实现,帮助读者掌握二分法的核心逻辑与边界处理技巧。

晚风叙旧发布于 2026/3/21更新于 2026/7/2061 浏览
二分算法:8 道经典题目详解与实战

1.二分查找

https://leetcode.cn/problems/binary-search/

在这里插入图片描述

思路

标准的二分查找。给定一个有序数组和目标值,每次选择数组的中间元素与目标值比较。如果中间元素等于目标值,则返回该索引;若中间元素小于目标值,则在右侧继续搜索;若中间元素大于目标值,则在左侧继续搜索。时间复杂度为 O(log n)。

步骤

初始化:设置 left 和 right 分别为数组的开头和结尾。 二分查找:计算中点 mid。 如果 nums[mid] 等于目标值,返回 mid。 如果 nums[mid] 小于目标值,更新 left = mid + 1。 如果 nums[mid] 大于目标值,更新 right = mid - 1。 终止条件:如果没有找到,返回 -1。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size(); // 获取数组的大小
        // 定义左右边界,left 是左边界,right 是右边界
        for (int left = 0, right = n - 1; left <= right;) {
            // 计算中间索引 mid,避免溢出的安全写法可以使用:mid = left + (right - left) / 2;
            int mid = (left + right) / 2;
            // 如果中间值小于目标值,说明目标值在右半部分,移动左边界到 mid + 1
            if (nums[mid] < target) left = mid + 1;
            // 如果中间值大于目标值,说明目标值在左半部分,移动右边界到 mid - 1
            if (nums[mid] > target) right = mid - 1;
            // 如果中间值等于目标值,返回当前中间值的索引
            if (nums[mid] == target) return mid;
        }
        // 如果没有找到目标值,返回 -1
         ;
    }
};
return
-1

2.在排序数组中查找元素的第一个和最后一个位置

https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/description/

在这里插入图片描述

思路

这是经典的'查找范围'问题,可以用两次二分查找解决。第一次找第一个出现位置,第二次找最后一个出现位置。时间复杂度为 O(log n),适合处理排序数组。

步骤

查找第一个位置:使用二分查找,找到目标值的第一个位置。 每次判断 nums[mid] 是否大于等于 target,是则向左移动,否则向右移动。 查找最后一个位置:使用二分查找,找到目标值的最后一个位置。 每次判断 nums[mid] 是否小于等于 target,是则向右移动,否则向左移动。 返回结果:如果找到两个位置,返回它们的范围,否则返回 [-1, -1]。

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        // 如果数组为空,直接返回 {-1, -1}
        if (nums.size() == 0) return {-1, -1};
        // 获取数组的大小
        int n = nums.size();
        // 初始化左右边界
        int left = 0, right = n - 1;
        // 查找左端点,目标是找到 target 第一次出现的位置
        while (left < right) {
            // 计算中间索引,防止溢出的安全写法
            int mid = left + (right - left) / 2;
            // 如果中间值小于目标值,说明目标值在右侧,将 left 移到 mid + 1
            if (nums[mid] < target) left = mid + 1;
            // 如果中间值大于等于目标值,右边界移动到 mid,继续查找
            if (nums[mid] >= target) right = mid;
        }
        // 如果左边界的值不等于 target,说明数组中没有该值,返回 {-1, -1}
        if (nums[left] != target) return {-1, -1};
        // 记录找到的目标值的起始位置
        int begin = left;
        // 查找右端点,目标是找到 target 最后一次出现的位置
        right = n - 1;
        // 重新初始化右边界
        // 使用二分查找找右边界
        while (left < right) {
            // 计算中间索引,为了确保 mid 偏向右侧,加 1
            int mid = left + (right - left + 1) / 2;
            // 如果中间值小于等于目标值,说明右边界可能在右侧,将 left 移动到 mid
            if (nums[mid] <= target) left = mid;
            // 如果中间值大于目标值,说明右边界在左侧,将 right 移到 mid - 1
            if (nums[mid] > target) right = mid - 1;
        }
        // 返回目标值的起始和结束位置
        return {begin, right};
    }
};

3.x 的平方根

https://leetcode.cn/problems/sqrtx/

在这里插入图片描述

思路

使用二分查找法求 x 的平方根。定义初始范围为 0,x,每次取中间值 m,计算 m²与 x 的比较。如果 m²小于 x,则移动左边界;如果 m²大于 x,则移动右边界。直至找到平方根或其整数部分。

步骤

初始化:设置 left 为 0,right 为 x。 二分查找:计算中点 mid。 如果 mid * mid 小于 x,说明平方根在右侧,更新 left = mid + 1。 如果 mid * mid 大于 x,说明平方根在左侧,更新 right = mid - 1。 终止条件:当 left 和 right 相遇时,取较小值作为结果的整数部分。

class Solution {
public:
    int mySqrt(int x) {
        // 定义二分查找的左右边界
        int left = 1, right = x;
        // 如果 x 小于 1,直接返回 0
        if (x < 1) return 0;
        // 开始二分查找
        while (left < right) {
            // 计算中间值,为了避免溢出,使用 left + (right - left + 1) / 2
            long long mid = left + (right - left + 1) / 2;
            // 如果 mid 的平方小于等于 x,说明 mid 可能是答案,或者答案在右侧,将 left 移动到 mid
            if (mid * mid <= x) left = mid;
            // 如果 mid 的平方大于 x,说明 mid 太大,答案在左侧,将 right 移动到 mid - 1
            else if (mid * mid > x) right = mid - 1;
        }
        // 返回找到的平方根的整数部分
        return left;
    }
};

4.搜索插入位置

https://leetcode.cn/problems/search-insert-position/description/

在这里插入图片描述

思路

给定一个有序数组和目标值,要求返回目标值在数组中的插入位置。如果数组中存在目标值,返回其索引;若不存在,返回其应该插入的位置。使用二分查找,找到第一个大于或等于目标值的位置。

步骤

初始化:使用 left 和 right 指针。 二分查找:计算中点 mid。 如果 nums[mid] 大于或等于目标值 target,则将 right 更新为 mid - 1。 否则,将 left 更新为 mid + 1。 终止条件:当 left 和 right 相遇时,left 即为目标值要插入的位置。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n = nums.size(); // 获取数组的大小
        // 定义左右边界,left 是左边界,right 是右边界
        int left = 0, right = n - 1;
        while (left <= right) {
            // 计算中间索引 mid,避免溢出的安全写法
            int mid = left + (right - left) / 2;
            // 如果中间值小于目标值,说明目标值在右半部分,移动左边界到 mid + 1
            if (nums[mid] < target) left = mid + 1;
            // 如果中间值大于目标值,说明目标值在左半部分,移动右边界到 mid - 1
            if (nums[mid] > target) right = mid - 1;
            // 如果中间值等于目标值,返回当前中间值的索引
            if (nums[mid] == target) return mid;
        }
        // 如果没有找到目标值,返回插入位置 left
        return left;
    }
};

5.山脉数组的峰顶索引

https://leetcode.cn/problems/peak-index-in-a-mountain-array/

在这里插入图片描述

思路

山脉数组是先递增后递减的数组,因此其峰顶就是数组中最大值的位置。可以使用二分查找,类似'寻找峰值'的思路,找到这个峰顶索引。

步骤

初始化:使用 left 和 right 指针,分别指向数组的开头和结尾。 二分查找:计算中点 mid。 如果 nums[mid] 大于 nums[mid + 1],峰顶在左侧,更新 right = mid。 如果 nums[mid] 小于 nums[mid + 1],峰顶在右侧,更新 left = mid + 1。 终止条件:当 left 和 right 相遇时,left 即为峰顶的索引。

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        // 获取数组大小
        int n = arr.size();
        // 定义左右边界。由于数组两端不能是峰值,山峰一定在 1 到 n-2 之间
        int left = 1, right = n - 2;
        // 当左边界小于右边界时,继续查找
        while (left < right) {
            // 计算中间位置,使用 left + (right - left + 1) / 2 可以避免溢出
            int mid = left + (right - left + 1) / 2;
            // 如果中间元素比左侧的前一个元素小,说明山峰在左边,右边界移动到 mid - 1
            if (arr[mid] < arr[mid - 1]) right = mid - 1;
            // 否则,山峰在右侧或当前位置,左边界移动到 mid
            else left = mid;
        }
        // 循环结束时,left 和 right 会指向同一个位置,这就是峰值的索引
        return left;
    }
};

6.寻找峰值

https://leetcode.cn/problems/find-peak-element/description/

在这里插入图片描述

思路

峰值定义为该元素比相邻元素大。可以使用二分查找的变种。每次选择中点,如果中点比其右侧元素小,则峰值在右侧;如果中点比其右侧元素大,则峰值在左侧。这样逐步缩小搜索范围,直至找到峰值。

步骤

初始化:定义 left 和 right 指针。 二分查找:每次计算中点 mid。 如果 nums[mid] 大于 nums[mid + 1],说明峰值在左侧或就是 mid,更新 right = mid。 如果 nums[mid] 小于 nums[mid + 1],说明峰值在右侧,更新 left = mid + 1。 终止条件:当 left 和 right 相遇时,left 即为峰值所在的位置。

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        // 初始化左右边界
        int left = 0, right = nums.size() - 1;
        // 二分查找
        while (left < right) {
            // 计算中间索引,避免溢出
            int mid = left + (right - left) / 2;
            // 如果中间值大于它右边的元素,说明峰值在左侧或当前元素是峰值,将右边界移到 mid
            if (nums[mid] > nums[mid + 1]) right = mid;
            // 如果中间值小于它右边的元素,说明峰值在右侧,将左边界移到 mid + 1
            else left = mid + 1;
        }
        // 返回最终找到的峰值索引
        return left;
    }
};

7.寻找旋转排序数组中的最小值

https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/description/

在这里插入图片描述

思路

旋转排序数组的特点是其包含两个有序的子数组(前一段大于后一段)。最小值通常出现在这两个有序子数组的交界处。可以使用二分查找,比较中点和右端点的值,若中点大于右端点,最小值在右侧;若中点小于右端点,最小值在左侧。

步骤

初始化:定义 left 和 right 指针。 二分查找:每次计算中点 mid。 如果 nums[mid] 大于 nums[right],说明最小值在右侧,更新 left = mid + 1。 否则,最小值在左侧或当前 mid 处,更新 right = mid。 终止条件:当 left 和 right 相遇时,left 即为最小值所在的位置。

class Solution {
public:
    int findMin(vector<int>& nums) {
        int n = nums.size(); // 获取数组大小
        int left = 0, right = n - 1; // 初始化左右边界
        // 二分查找
        while (left < right) {
            int mid = left + (right - left) / 2; // 计算中间索引,避免溢出
            // 如果中间值大于最右侧值,说明最小值在右侧,更新 left
            if (nums[mid] > nums[right]) left = mid + 1;
            // 否则,最小值在左侧或当前 mid 处
            else right = mid;
        }
        // 最小值在 left 处
        return nums[left];
    }
};

8.JZ53(2) 缺失的数字

《剑指 offer 面试题 53-II》 题目类型:0〜n-1 中缺失的数字(面试题 53 - II) 因为这题作者在 leetcode 中未找到这题原题,不过有一道类似题目 (这题在 leetcode 消失的原因是剑指 offer 在 leetcode 上下架了) https://leetcode.cn/problems/que-shi-de-shu-zi-lcof/

在这里插入图片描述

思路

因为数组是排好序的,且数字从 0 到 n-1 连续,可以使用二分查找找到缺失的数字。如果 nums[mid] == mid,说明缺失的数字在右侧;否则在左侧。

class Solution {
public:
    // 该函数通过二分查找处理缺失数字问题,返回缺失的数字
    int missingNumber(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;
        }
        // 如果最终找到的位置的索引值等于该位置的记录值,则返回 left + 1,否则返回 left
        return left == records[left] ? left + 1 : left;
    }
};

此外这题还可以用 4 种 O(n) 时间复杂度方法去求:第 1 种:直接遍历寻找,第 2 种:哈希,第 3 种:异或,第 4 种:等差求和。

目录

  1. 1.二分查找
  2. 思路
  3. 步骤
  4. 2.在排序数组中查找元素的第一个和最后一个位置
  5. 思路
  6. 步骤
  7. 3.x 的平方根
  8. 思路
  9. 步骤
  10. 4.搜索插入位置
  11. 思路
  12. 步骤
  13. 5.山脉数组的峰顶索引
  14. 思路
  15. 步骤
  16. 6.寻找峰值
  17. 思路
  18. 步骤
  19. 7.寻找旋转排序数组中的最小值
  20. 思路
  21. 步骤
  22. 8.JZ53(2) 缺失的数字
  23. 思路
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • whisperX 入门指南:从安装配置到语音识别实战
  • 修复 Microsoft Visual C++ 2022 X86 Minimum Runtime 安装错误
  • Agent 操控手机与电脑屏幕的技术解析与应用指南
  • Adobe 联合伯克利研发 AI 工具识别面部修图
  • 基于 Spring Boot 与 WebSocket 的 Java 实时聊天室设计实践
  • OpenClaw 安装部署全流程:搭建自托管 AI 助手网关
  • 基于 Cursor 的 Web 背单词应用开发实战
  • 顺序表与链表核心算法实战:双指针与快慢指针详解
  • 前端面试高频场景题汇总
  • Scala 内建控制结构:if 表达式实战
  • OpenClaw 新手入门:环境搭建、模型配置与远程访问
  • Android 免 Root 自动抢红包工具 AutoRobRedPackage 使用指南
  • Linux 环境下 C/C++ 编译流程与链接机制详解
  • 无人机植物病害目标检测数据集(1500 张已标注)
  • 基于 FastGPT 与 MCP 协议构建工具增强型智能体
  • Prompt Engineering 入门与实战:基于 Node.js 的 LLM 应用开发
  • 《大模型应用开发极简入门》:LLM 应用开发指南书评
  • 统一 API 接入大模型:解决多厂商兼容与成本难题
  • 2026 低代码选型指南:AI 与低代码双向赋能
  • AIGC 探索:AI 生成内容的未来市场与技术应用

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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