news 2026/8/10 3:57:14

【算法题】二分

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【算法题】二分

二分查找是高效解决有序/局部有序数组问题的经典算法,核心思想是通过不断缩小“可能包含目标的区间”,将时间复杂度从暴力遍历的O(n)O(n)O(n)优化到O(log⁡n)O(\log n)O(logn)
它的适用场景非常广泛:不仅能解决“查找目标值”这类基础问题,还能处理“找边界”“找极值”“旋转数组”等复杂场景。本文将通过7道经典题目,拆解二分查找在不同场景下的解题思路与代码实现。

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

题目描述:
给定非递减排序的整数数组nums和目标值target,找出target在数组中的开始位置和结束位置;若不存在则返回[-1, -1]。要求时间复杂度为O(log⁡n)O(\log n)O(logn)

示例

  • 输入:nums = [5,7,7,8,8,10], target = 8,输出:[3,4]
  • 输入:nums = [5,7,7,8,8,10], target = 6,输出:[-1,-1]

解题思路:
通过两次二分查找分别确定左边界和右边界:

  1. 找左边界:二分找第一个等于target的位置。若nums[mid] < target,左指针右移;否则右指针左移,最终左指针即为左边界。
  2. 找右边界:二分找最后一个等于target的位置。若nums[mid] <= target,左指针右移;否则右指针左移,最终右指针即为右边界。
  3. 若左边界对应的元素不是target,直接返回[-1,-1]

完整代码:

classSolution{public:vector<int>searchRange(vector<int>&nums,inttarget){if(nums.size()==0)return{-1,-1};intbegin=0;intleft=0,right=nums.size()-1;// 找左边界while(left<right){intmid=left+(right-left)/2;if(nums[mid]<target)left=mid+1;elseright=mid;}if(nums[left]!=target)return{-1,-1};elsebegin=left;// 找右边界right=nums.size()-1;while(left<right){intmid=left+(right-left+1)/2;if(nums[mid]<=target)left=mid;elseright=mid-1;}return{begin,right};}};

复杂度分析:

  • 时间复杂度:O(log⁡n)O(\log n)O(logn),两次二分查找各占O(log⁡n)O(\log n)O(logn)
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

二、x 的平方根

题目描述:
给定非负整数x,计算并返回其算术平方根的整数部分(舍去小数部分),不允许使用内置指数函数或运算符。

示例

  • 输入:x = 4,输出:2
  • 输入:x = 8,输出:2(8的平方根是2.828…,取整数部分)

解题思路:
通过二分查找找最大的整数mid,使得mid² <= x

  1. 边界条件:若x < 1,直接返回0;否则二分区间为[1, x]
  2. 二分过程:计算mid = left + (right - left + 1) / 2(避免死循环),用long long存储mid * mid防止整数溢出;若mid * mid <= x,左指针右移(保留当前候选值),否则右指针左移。

完整代码:

classSolution{public:intmySqrt(intx){if(x<1)return0;intleft=1,right=x;while(left<right){longlongmid=left+(right-left+1)/2;if(mid*mid<=x)left=mid;elseright=mid-1;}returnleft;}};

复杂度分析:

  • 时间复杂度:O(log⁡x)O(\log x)O(logx),二分区间大小为x,每次缩小一半。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

三、搜索插入位置

题目描述:
给定排序数组nums和目标值target,找到target在数组中的索引;若不存在,则返回其按顺序插入的位置。要求时间复杂度为O(log⁡n)O(\log n)O(logn)

示例

  • 输入:nums = [1,3,5,6], target = 5,输出:2
  • 输入:nums = [1,3,5,6], target = 2,输出:1

解题思路:
通过二分查找找第一个大于等于target的位置

  • nums[mid] < target,说明target在右边,左指针右移;否则右指针左移。
  • 最终左指针即为目标位置(若nums[left] < target,则插入到left+1,否则插入到left)。

完整代码:

classSolution{public:intsearchInsert(vector<int>&nums,inttarget){intleft=0,right=nums.size()-1;while(left<right){intmid=left+(right-left)/2;if(nums[mid]<target)left=mid+1;elseright=mid;}returnnums[left]<target?left+1:left;}};

复杂度分析:

  • 时间复杂度:O(log⁡n)O(\log n)O(logn),二分遍历数组。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

四、山脉数组的峰顶索引

题目描述:
给定山脉数组arr(先递增后递减),返回峰值元素的下标,要求时间复杂度为O(log⁡n)O(\log n)O(logn)

示例

  • 输入:arr = [0,1,0],输出:1
  • 输入:arr = [0,2,1,0],输出:1

解题思路:
山脉数组的峰值满足arr[mid] > arr[mid-1]arr[mid] > arr[mid+1],通过二分缩小范围:

  • 二分区间为[1, arr.size()-2](避免越界),比较arr[mid]arr[mid-1]
    • arr[mid] > arr[mid-1],说明峰值在右边,左指针右移。
    • 否则说明峰值在左边,右指针左移。
  • 最终左指针即为峰值下标。

完整代码:

classSolution{public:intpeakIndexInMountainArray(vector<int>&arr){intleft=1,right=arr.size()-2;while(left<right){intmid=left+(right-left+1)/2;if(arr[mid]>arr[mid-1])left=mid;elseright=mid-1;}returnleft;}};

复杂度分析:

  • 时间复杂度:O(log⁡n)O(\log n)O(logn),二分遍历数组。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

五、寻找峰值

题目描述:
峰值元素是指严格大于左右相邻值的元素,给定数组nums,返回任意一个峰值的下标。假设nums[-1] = nums[n] = -∞,要求时间复杂度为O(log⁡n)O(\log n)O(logn)

示例

  • 输入:nums = [1,2,3,1],输出:2
  • 输入:nums = [1,2,1,3,5,6,4],输出:15

解题思路:
利用“边界为负无穷”的假设,通过二分找峰值:

  • 二分区间为[0, nums.size()-1],比较nums[mid]nums[mid+1]
    • nums[mid] > nums[mid+1],说明峰值在左边(包括mid),右指针左移。
    • 否则说明峰值在右边,左指针右移。
  • 最终左指针即为峰值下标(必然存在峰值)。

完整代码:

classSolution{public:intfindPeakElement(vector<int>&nums){intleft=0,right=nums.size()-1;while(left<right){intmid=left+(right-left)/2;if(nums[mid]>nums[mid+1])right=mid;elseleft=mid+1;}returnleft;}};

复杂度分析:

  • 时间复杂度:O(log⁡n)O(\log n)O(logn),二分遍历数组。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

六、寻找旋转排序数组中的最小值

题目描述:
给定升序旋转后的数组nums(元素互不相同),返回数组中的最小元素,要求时间复杂度为O(log⁡n)O(\log n)O(logn)

示例

  • 输入:nums = [3,4,5,1,2],输出:1
  • 输入:nums = [4,5,6,7,0,1,2],输出:0

解题思路:
旋转后的数组分为“左升序段”和“右升序段”,最小值是右段的第一个元素:

  • 二分区间为[0, nums.size()-1],比较nums[mid]nums.back()(最后一个元素):
    • nums[mid] > nums.back(),说明mid在左段,最小值在右边,左指针右移。
    • 否则说明mid在右段,最小值在左边(包括mid),右指针左移。
  • 最终左指针即为最小值的下标。

完整代码:

classSolution{public:intfindMin(vector<int>&nums){intleft=0,right=nums.size()-1;while(left<right){intmid=left+(right-left)/2;if(nums[mid]>nums[nums.size()-1])left=mid+1;elseright=mid;}returnnums[left];}};

复杂度分析:

  • 时间复杂度:O(log⁡n)O(\log n)O(logn),二分遍历数组。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。

七、点名

题目描述:
班级n位同学的学号为0~n-1,点名结果记录于升序数组records,仅一位同学缺席,返回其学号。

示例

  • 输入:records = [0,1,2,3,5],输出:4
  • 输入:records = [0,1,2,3,4,5,6,8],输出:7

解题思路:
正常情况下records[mid] == mid,缺席的学号会打破该关系:

  • 二分区间为[0, records.size()-1],比较records[mid]mid
    • records[mid] == mid,说明缺席在右边,左指针右移。
    • 否则说明缺席在左边(包括mid),右指针左移。
  • 最终若records[left] == left,缺席学号为left+1;否则为left

完整代码:

classSolution{public:inttakeAttendance(vector<int>&records){intleft=0,right=records.size()-1;while(left<right){intmid=left+(right-left)/2;if(records[mid]==mid)left=mid+1;elseright=mid;}returnrecords[left]==left?left+1:left;}};

复杂度分析:

  • 时间复杂度:O(log⁡n)O(\log n)O(logn),二分遍历数组。
  • 空间复杂度:O(1)O(1)O(1),仅用常数级额外变量。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/2 8:47:40

System76发布Pop!_OS 24.04 LTS版搭载全新Rust构建的桌面环境

经过长时间的开发&#xff0c;第一个完全基于Rust构建的桌面环境1.0版本终于发布&#xff0c;整体表现令人印象深刻。上周末&#xff0c;System76正式发布了其内部开发的Ubuntu衍生版本的长期支持版本&#xff0c;同时推出了完全用Rust重新实现的内部桌面环境COSMIC的"Epo…

作者头像 李华
网站建设 2026/8/5 16:18:24

Pr字幕样式如何统一修改?简单3步,新手也能一次改完

如果你搜索到这篇文章&#xff0c;大概率只有一个想法&#xff1a; 字幕太多了&#xff0c;不想一条一条改。 不管是改字体、颜色&#xff0c;还是统一位置&#xff0c;只要字幕数量一多&#xff0c;用 Pr 原生方式操作&#xff0c;都会变得又慢又容易出错。 下面这套方法&…

作者头像 李华
网站建设 2026/8/4 11:51:32

低功耗设计:手机控制LED屏的节能策略

手机控制LED屏如何省电&#xff1f;揭秘三大低功耗核心技术你有没有想过&#xff0c;一块小小的LED显示屏&#xff0c;为什么能让智能手环撑上一周&#xff0c;而有些电子标签却几个月都不换电池&#xff1f;在物联网设备遍地开花的今天&#xff0c;手机通过蓝牙控制LED屏已经不…

作者头像 李华
网站建设 2026/7/31 6:26:02

MyBatis实战精讲:完整用户CRUD操作全解析

在Java持久层开发领域&#xff0c;MyBatis凭借其轻量化、高灵活性的特性&#xff0c;成为连接Java应用与数据库的主流框架。它摒弃了JDBC繁琐的代码编写&#xff0c;通过“接口XML”的映射模式&#xff0c;让开发者专注于SQL逻辑本身。本文将基于一套完整的用户数据操作代码&am…

作者头像 李华
网站建设 2026/8/5 5:02:14

【2025 arXiv】Reasoning Within the Mind: Dynamic Multimodal Interleaving in Latent Space

这篇论文的核心突破在于将多模态推理从“显式的文本生成”转移到了“隐式的潜在空间优化”,并利用“置信度”这一信号实现了类似人类的动态视觉回溯,从而兼顾了推理的深度、准确性和效率。 paper: https://arxiv.org/pdf/2512.12623 code: https://github.com/eric-ai-lab/DM…

作者头像 李华
网站建设 2026/8/4 1:24:34

构建安全可控的企业知识库:anything-llm解决方案

构建安全可控的企业知识库&#xff1a;anything-llm解决方案 在企业数字化转型的浪潮中&#xff0c;一个现实问题正日益凸显&#xff1a;员工每天花数小时翻找政策文件、客服重复回答相同问题、新成员难以快速掌握内部流程——信息就在那里&#xff0c;却“看得见、摸不着”。传…

作者头像 李华