文章目录

  • 1. 简介
  • 2. 最简单的二分查找
  • 3. 4种常见的二分查找变形问题
    • 3.1 查找第一个值等于给定值的元素
    • 3.2 查找最后一个值等于给定值的元素
    • 3.3 查找第一个大于等于给定值的元素
    • 3.4 查找最后一个小于等于给定值的元素
  • Reference

1. 简介

  • 二分查找(Binary Search)算法,也叫折半查找算法,二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想,每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0

  • 二分查找的时间复杂度为: O ( l o g n ) O(logn) O(logn)

  • 二分容易出错的细节:循环退出条件、区间上下界更新方法、返回值选择

  • 二分查找的应用场景比较有限:底层必须依赖数组,并且要求数据有序;对于较小规模的数据查找,直接使用顺序遍历就可以了,二分查找的优势并不明显,二分查找更适合处理静态数据,也就是没有频繁的数据插入、删除操作

2. 最简单的二分查找

  • 在不存在重复元素的有序数组中,查找等于给定值的元素
/*** 在不存在重复元素的有序数组中,查找等于给定值的元素** @param nums* @param target* @return*/
int binarySearch(int[] nums, int target) {int left = 0;int right = nums.length - 1; // 在[left, right]的范围里寻找targetwhile (left <= right) { // 当left==right时,区间[left,right]依然有效int mid = (left + right) >>> 1;if (nums[mid] == target) {return mid;} else if (nums[mid] < target) {left = mid + 1; // target在[mid+1,right]中} else if (nums[mid] > target) {right = mid - 1; // target在[left, mid-1]中}}return -1;
}

3. 4种常见的二分查找变形问题

3.1 查找第一个值等于给定值的元素

  • 有序数据集合中存在重复的数据,希望找到第一个值等于给定值的数据

    • 比如下面这样一个有序数组,其中, a[5], a[6], a[7]的值都等于8,是重复的数据。希望查找第一个等于8的数据,也就是下标是5的元素

    /*** 查找第一个值等于给定值的元素* @param nums* @param target* @return*/int left_binarySearch(int[] nums, int target) {int left = 0;int right = nums.length - 1;while (left <= right) {int mid = (left + right) >>> 1;if (nums[mid] > target) {right = mid - 1;} else if (nums[mid] < target) {left = mid + 1;} else {if ((mid == 0) || (nums[mid-1] != target)) {return mid;} else {right = mid - 1;}}}return -1;}
  • nums[mid] > target时,更新right=mid-1
  • nums[mid] < target时,更新left=mid+1
  • nums[mid]==target时,需要确认一下nums[mid]是不是第一个等于给定值的元素
    • mid = 0,这个元素已经是数组的第一个元素,肯定是要找的
    • mid != 0 且 前一个元素nums[mid-1] != target,也说明nums[mid]就是要找的第一个值等于给定值的元素
    • mid != 0nums[mid-1]==target,说明此时的nums[mid]不是第一个值等于给定值的元素,就更新right=mid-1,要找的元素肯定出现在 [ l e f t , m i d − 1 ] [left, mid-1] [left,mid−1]之间

3.2 查找最后一个值等于给定值的元素

  • 有序数据集合中存在重复的数据,希望查找最后一个值等于给定值的元素
/*** 查找最后一个值等于给定值的元素* @param nums* @param target* @return*/
int right_binarySearch(int[] nums, int target) {int left = 0;int right = nums.length - 1;while (left <= right) {int mid = (left + right) >>> 1;if (nums[mid] > target) {right = mid - 1;} else if (nums[mid] < target) {left = mid + 1;} else {if ((mid == nums.length-1) || (nums[mid+1] != target)) {return mid;} else {left = mid+1;}}}return -1;
}
  • nums[mid] > target时,更新right=mid-1
  • nums[mid] < target时,更新left=mid+1
  • nums[mid]==target时,需要确认一下nums[mid]是不是最后一个等于给定值的元素
    • 如果nums[mid]这个元素已经是数组中的最后一个元素了,那它肯定是我们要找的
    • 如果nums[mid]的后一个元素nums[mid+1]不等于target,那也说明nums[mid]就是要找的最后一个值等于给定值的元素
    • 如果经过检查之后,发现nums[mid]后面的一个元素nums[mid+1]也等于target,那说明当前的这个nums[mid]并不是最后一个值等于给定值的元素。就更新left=mid+1,因为要找的元素肯定出现在 [ m i d + 1 , h i g h ] [mid+1, high] [mid+1,high]之间

3.3 查找第一个大于等于给定值的元素

  • 在有序数组中,查找第一个大于等于给定值的元素。比如,数组中存储的这样一个序列: 3, 4, 6, 7, 10。如果查找第一个大于等于5的元素,那就是6
/*** 查找第一个大于等于给定值的元素* @param nums* @param target* @return*/
int greater_binarySearch(int[] nums, int target) {int left = 0;int right = nums.length - 1;while (left <= right) {int mid = (left + right) >>> 1;if (nums[mid] >= target) {if ((mid == 0) || (nums[mid-1] < target)) {return mid;} else {right = mid - 1;}} else {left = mid + 1;}}return -1;
}
  • 如果nums[mid] < target,那要查找的值肯定在 [ m i d + 1 , r i g h t ] [mid+1, right] [mid+1,right]之间,所以,更新left=mid+1
  • 如果nums[mid] >= target,要先看下这个nums[mid]是不是要找的第一个值大于等于给定值的元素
    • 如果nums[mid]前面已经没有元素,或者前面一个元素小于要查找的值target,那nums[mid]就是要找的
      元素
    • 如果nums[mid-1] >= target,那说明要查找的元素在 [ l e f t , m i d − 1 ] [left, mid-1] [left,mid−1]之间,所以,更新right=mid-1

3.4 查找最后一个小于等于给定值的元素

  • 在有序数组中,查找最后一个小于等于给定值的元素。比如,数组中存储了这样一组数据: 3, 5, 6, 8, 9, 10。最后一个小于等于7的元素就是6
/*** 查找最后一个小于等于给定值的元素* @param nums* @param target* @return*/
int le_binarySearch(int[] nums, int target) {int left = 0;int right = nums.length - 1;while (left <= right) {int mid = (left + right) >>> 1;if (nums[mid] > target) {right = mid - 1;} else {if ((mid == nums.length-1) || (nums[mid+1] > target)) {return mid;} else {left = mid + 1;}}}return -1;
}

Reference

  • 数据结构与算法之美

二分查找:思路很简单,细节是魔鬼相关推荐

  1. 【算法】详解二分查找算法(思路很简单,细节是魔鬼)

    我周围的人几乎都认为二分查找很简单,但事实真的如此吗?二分查找真的很简单吗?并不简单.看看 Knuth 大佬(发明 KMP 算法的那位)怎么说的: Although the basic idea of ...

  2. 34. 在排序数组中查找元素的第一个和最后一个位置012(二分查找+思路+详解+两种方法)Come Baby!!!!!!!! !

    一:题目 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 如果数组中不存在目标值 target,返回 [-1, -1]. 进阶: 你 ...

  3. 81. 搜索旋转排序数组 II(014)二分查找+思路+详解+二种做法

    一:题目 已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同. 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 ...

  4. 33. 搜索旋转排序数组(013)二分查找+思路详解+来干了这杯代码!!!!!!

    一:题目 整数数组 nums 按升序排列,数组中的值 互不相同 . 在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变 ...

  5. 二分查找和二分答案(洛谷)

    细节好可怕~ 二分查找算法的细节剖析_JackComeOn的博客-CSDN博客原文:https://www.cnblogs.com/kyoner/p/11080078.html我周围的人几乎都认为二分 ...

  6. 查找算法——二分查找(原理+源码)

    1,原理 二分查找又称折半查找,只适用于有序数组.二分查找原理很简单,针对有序数组的查找效率也很高.具体原理为,每次拿目标数值(以下用value表示)与数组中间位置的数据(以下用arry[mid]表示 ...

  7. 魔鬼一样的二分查找模板

    Although the basic idea of binary search is comparatively straightforward, the details can be surpri ...

  8. LeetCode面试刷题技巧-二分查找算法代码思路解析

    二分查找的思想 提及二分查找算法,我想大部分人都不陌生,就算不是学计算机的,基本上也都使用过二分查找的思想,不信的话,且听我慢慢为你道来. 不知道你有没有玩过这样一个游戏,猜数字.就是说一个人心里想了 ...

  9. 六十七、二分查找算法及其四个变形问题

    @Author:Runsen 编程的本质来源于算法,而算法的本质来源于数学,编程只不过将数学题进行代码化. ---- Runsen 文章目录 二分法查找 二分查找的变形问题 查找第一个等于给定值的元素 ...

最新文章

  1. Windows 远程桌面连接数限制
  2. LAMP之二:LAMP的性能测试以及安装xcache,为php加速
  3. 仿联想商城laravel实战---7、lavarel中如何给用户发送邮件
  4. codeforces Round#429 (Div2)
  5. BA-Alerton系统简介
  6. pandas 数据索引与选取
  7. 关于页面布局的一些注意点
  8. bigpipe提升网站响应速度
  9. ROS笔记(20) Kinect仿真
  10. 4.1 深层神经网络
  11. maven 编译命令
  12. 矩阵运算_Sophus库的使用
  13. o(n)复杂度下实现数组去除重复项
  14. 【原】数据分析/数据挖掘/机器学习---- 必读书目
  15. InnoDB存储引擎架构
  16. 逻辑回归算法识别Minst手写集
  17. Windows 10不能安装mini版迅雷的解决方法
  18. java导出csv文件,使用Excel打开中文乱码
  19. 北京车管所 与 换领驾驶证过程
  20. WMS系统是什么——史上最全WMS介绍

热门文章

  1. 【架构分析】DALI 源码分析
  2. 一些好用的软件推荐给你
  3. centos 开机运行卡住
  4. centos8输入正确账号和密码登录报错
  5. HTTP请求报文结构和请求方法(通俗易懂)!!
  6. 写了个使用QuickSilver发表饭否消息的脚本..
  7. Artifact xxxx:war exploded: Artifact is deployed successfully
  8. 完美解决夏天电脑cpu发烫问题
  9. “xxx对用户透明 的真正意思
  10. 医疗教学展示培训报告说明ppt模板 毕业答辩PPT 科研成果展示PPT图形素材打包