当前位置: 首页 > news >正文

LeetCode-704-二分查找

题目链接

题目描述

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果 target 存在返回下标,否则返回 -1

你必须编写一个具有 O(log n) 时间复杂度的算法。

示例1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例2:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

解题思路

将该题简化,我们会发现以下几个关键词:有序数组、无重复元素、O(log n),这是一道很典型的二分查找,借由该题,我们将详细叙述二分的思想。

1. 二分查找的基本原理

二分查找(Binary Search)是一种基于分治策略的查找算法,其核心思想是通过不断将有序数据集对半分割来快速定位目标元素
。算法要求数据必须预先排序(通常为升序或降序),从而利用有序性快速缩小搜索范围。

数学基础​​:对于一个长度为n的有序数组,二分查找最多需要⌊log₂n⌋+1次比较
。例如,当n=1000时,最多只需10次比较即可完成查找,而线性查找可能需要1000次比较。这种指数级的效率提升使得二分查找在处理大规模数据时极具优势。

适用场景​​:

  • 数据结构支持随机访问(如数组、向量)
  • 数据必须有序(若无序需先排序)
  • 存在明确的判断条件(能确定目标在左半区还是右半区)

2. 二分查找的两种主要实现方式

2.1 左闭右闭区间 [left, right]

这是最直观的实现方式,搜索区间包含左右边界指向的元素。

​​算法流程​​:

​1.​初始化边界​​:设置左边界left = 0,右边界right = nums.length - 1

​2.​循环条件​​:当left ≤ right时继续查找(确保搜索区间有效),因为left == right是有意义的

​3. ​计算中间位置​​:mid = left + ((right - left)>>1)(防止整数溢出的安全写法,还涉及到符号运算顺序级)

​4.​比较与判断​​:

  • 如果arr[mid] == target,查找成功,返回mid
  • 如果arr[mid] < target,说明目标在右侧,更新left = mid + 1 (此时mid值一定不是目标值,那么接下来要查找的左区间结束下标位置就是 middle + 1,遵循区间左闭右闭)
  • 如果arr[mid] > target,说明目标在左侧,更新right = mid - 1

​​5.终止条件​​:如果循环结束仍未找到目标,返回-1表示查找失败

代码实现

class Solution {public int search(int[] nums, int target) {int left = 0;int right = nums.length - 1;while(left <= right){int mid = left + ((right - left) >> 1); // 防止溢出if(nums[mid] == target)return mid;else if (nums[mid] < target)left =  mid + 1;else right = mid - 1;}return -1;}
}

2.2 左闭右开区间 [left, right)

这种实现方式中,搜索区间包含左边界指向的元素,但不包含右边界指向的元素。

​​算法流程​​:

1.​初始化边界​​:设置left = 0,right = nums.length(右边界不包含)

2.循环条件​​:当left < right时继续查找(这里使用 < ,因为left == right在区间[left, right)是没有意义的)

3.​​计算中间位置

4.​比较与判断​​:

  • 如果arr[mid] == target,查找成功,返回mid
  • 如果arr[mid] < target,更新left = mid + 1
  • 如果arr[mid] > target,更新right = mid(注意不是mid-1),因为当前arr[mid]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为mid,即:下一个查询区间不会去比较arr[mid]

5.终止条件​​:循环结束时仍未找到目标,返回-1

​​代码实现​​:

class Solution{public int search(int [] nums, int target){int left = 0;int right = nums.length;//有问题 int right = nums.length - 1; while (left < right){int mid = left + ((right  - left) >> 1);if(nums[mid] == target)return mid;else if (nums[mid] < target)left = mid + 1;else right = mid;}return -1;}
}

2.3 两种实现方法对比

特性左闭右闭区间 [left, right]左闭右开区间 [left, right)
初始右边界right = nums.length - 1right = nums.length
循环条件while (left <= right)while (left < right)
边界更新 (nums[mid] > target)right = mid - 1right = mid
区间为空的条件left > rightleft == right
mid 计算偏好(防死循环)mid = left + (right - left) / 2mid = left + (right - left + 1) / 2 均可必须使用 mid = left + (right - left) / 2(偏左)

3. 关键点总结

3.1 防止整数溢出

计算中间位置时,应使用left + (right - left) / 2而非(left + right) / 2,这样可以避免当left和right都很大时相加导致的整数溢出。

3.2 循环条件的选择

循环条件必须与区间定义保持一致。左闭右闭区间使用left <= right,因为当left等于right时区间仍包含一个元素;左闭右开区间使用left < right,因为当left等于right时区间为空。

3.3 边界更新的逻辑

边界更新必须确保每次迭代都能缩小搜索范围,同时不遗漏可能的目标元素。特别是在左闭右开区间中,当目标值小于中间值时,右边界更新为mid而非mid-1,因为右边界本身不指向待检查元素。

更多力扣算法解析,尽在https://saberanakin.github.io/

http://www.dtcms.com/a/461705.html

相关文章:

  • 老题新解|大整数加法
  • 常见python 排序
  • windows安装claude踩到的坑
  • 专业外贸网站建设公司价格深圳谷歌seo推广
  • 为什么需求文档总是不完整,有哪些解法
  • 88-python电网可视化项目-8-2
  • 计算机专业可考证书汇总及建议
  • 爱站网是干嘛的网站建设中 页面
  • 【agent】AI 数字人构建2:MDM与MNN
  • 配电安全“隐形哨兵”上线!RCMX-ONE剩余电流监视器,守护每一度电的安心
  • 视频封面制作网站wordpress怎么考别人的
  • 专做眼镜的网站临城网络营销怎么做
  • Oracle VirtualBox异常关闭后无法启动解决办法
  • 微信小程序开发从零基础到项目发布的全流程实战教程(五)
  • 边缘计算双雄:CDN与PCDN
  • LeetCode 面试经典 150_哈希表_存在重复元素 II(46_219_C++_简单)
  • 网站2个页面做首页广元 网站建设
  • HTML应用指南:利用POST请求获取全国中信银行网点位置信息
  • 加油站小程序上线即闲置?3 大核心功能 + 运营落地策略
  • 做淘宝客导购网站宁夏百度公司
  • 使用 Flask 实现本机 PyTorch 模型部署:从服务端搭建到客户端调用
  • sql题目练习——多表查询
  • c 做网站加载多个图片网站开发实战第二章
  • 精通C语言(3. 自定义类型:联合体和枚举)
  • 认知事物的三个层次
  • 做数学题目在哪个网站好设计好的装修公司
  • 09.Linux环境变量
  • 11、规划过程组(4):风险
  • HT8698 立体声 D 类音频功率放大器:性能参数介绍
  • 做亚克力在那个网站上好上海建工一建集团有限公司