二分查找很常见,思路也很清晰。
但是还是那句经典的话: 思路越简单,细节越丰富

二分查找 "恶心"人的地方有三个:

  1. while 里面是left <= right 还是 left < right ?
  2. 缩小区间的时候,left 和 right 要不要带上mid?(最可能引起死循环的原因)
  3. 返回啥 ? left 还是 right ?

有时候凭感觉写的对了,有时候就错了,这就是传说中的7分天注定,3分靠感觉!
coding的最终奥义,无脑编程!

拿最常用的三个 二分查找场景

  1. 寻找一个数
  2. 寻找一个数的最左侧出现的地方(左侧边界)
  3. 寻找一个数的最左侧出现的地方(右侧边界)

这三个场景其实可以抽象成两个:

  1. 找到这个数就返回
  2. 找到这个数不返回,继续往左/右找

废话不说,先上菜!
(我把所有可能产生疑问的地方标注出来单一在后面解释。)

case.1int binary_search(int[] nums, int target) {int left = 0, right = nums.length - 1; while(left <= right) { int mid = ((right - left) >> 1) + left;if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {right = mid - 1; } else if(nums[mid] == target) {return mid; }}return -1; //直接返回查找失败
}
------------------------------------------------
case.2int left_bound(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) { // note1int mid = ((right - left) >> 1) + left;if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {right = mid - 1; // note2} else if (nums[mid] == target) {right = mid - 1; // note3 不返回,锁定边界}}// note4  最后检查 left 越界的情况if (left >= nums.length || nums[left] != target)return -1;return left;
}------------------------------------------------------
case.3int right_bound(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = ((right - left) >> 1) + left;if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {right = mid - 1;} else if (nums[mid] == target) {left = mid + 1; // 不返回,锁定边界}}// 最后要检查 right 越界的情况if (right < 0 || nums[right] != target)return -1;return right;
}

note1: 什么时候取 <= ?

大多数情况下,如果你的left和right初始值都是有效的索引,就用 <= 。
其实,简单来说就是 right 取 nums.length - 1, 这就可以 <=,
这时的while结束条件是 left = right + 1; 这个知识点很重要!!!

对于后面两个题目,在 nums[mid]==target时 start或者end的更新 跟这个点有很大关系!!

note2 & note 3: 更新start或者end的时候,带不带mid?

这里以第2题 寻找左边界举例子,第3题同理。
首先,note2这里 nums[mid] > target时,target一定不可能在[mid, right]这个闭区间出现了,所以 mid 自然取不到,right = mid - 1;

但是note3这里 为什么 nums[mid] == target 的时候 也不带mid了呢?

如果这里right = mid的话,对于 1 2 2 2 3 搜 1,会死循环(自己模拟一下)

你可能会担心 取right=mid - 1的话, mid左边如果不会再出现target了(此时的mid就是答案),就永远都回不到mid了,这不就找不到正确答案了吗?

实际上,不用担心,这就是为什么说上面 while结束条件是 left = right + 1;很重要!

我们注意到 while 的终止条件:left<=right 更清晰一点的是退出while的条件是 left=right+1

也就是说,如果此时这个mid左边没有target了,这个right在被赋值完mid-1以后,就不会再更新(往左前进了)因为此时[left, right]闭区间的所有数都小于target,更新的一直是left,right会一直停在mid-1的位置。

left一直往右前进更新,直到 left=right 时进入循环,发现nums[mid]还是<target, left继续前进,变成right + 1,退出循环!

退出循环的时候,left = right + 1, right+1不就是mid吗!!!!

note 4 返回啥 ?

    // note4  最后检查 left 越界的情况if (left >= nums.length || nums[left] != target)return -1;return left;

left>= nums.length 对应 找的target比nums所有数都大,left一直前进;
nums[left] != target 对应,找的target比nums所有数都小,此时left一直指向0,right一直往左走;

简单点,nums[mid]==target 的时候,您返回left,就更新right!反之同理;


所以。其实后两个问题归根结底还是因为
nums[mid]==target的时候没有返回,而是继续搜索!!!

所以 此时的区间收缩不能按照上面nums[mid] > 或 < target的情况理论判断,要结合实际!

二分查找边界问题总结相关推荐

  1. tag数组-刷题预备知识-4.一通百通解决二分查找问题

    文章目录 1. 二分法查找法的基本思想 2. 二分查找的时间复杂度 3. 二分查找的几个模版 3.1 模板一: 标准的二分查找 3.2 模板二: 二分查找边界(左边界, 右边界, 或是左右边界) 3. ...

  2. 34. 二分查找左右边界

    二分查找框架 int binary_search(int[] nums, int target) {int left = 0, right = nums.length - 1; while(left ...

  3. 左右边界二分查找小总结

    普通二分查找比较简单,应用于查找某值是否存在于数组中: 但是普通二分查找也有缺点,就是当有多个target值存在,想要返回target左右边界的下标时,普通二分查找就没有办法完成,虽然说可以在查找到某 ...

  4. 经典算法之左边界二分查找法(俗称左边界二分搜索法)

    经典算法之左边界二分查找法(俗称左边界二分搜索法) 文章目录 经典算法之左边界二分查找法(俗称左边界二分搜索法) 前言 一.什么左边界二分查找法? 二.代码实现 总结 前言 就算法而言,我们主要学习的 ...

  5. 二分查找及查找左、右边界

    目录 二分查找 概念: 详细举例: 那么问题来了 实现代码: 查找左右边界: 概念: 举例: 编写思路: 实现代码: 二分查找 概念: 通过将一组"有序"的'组'不断的一分为二的方 ...

  6. 经典算法之右边界二分查找法(俗称基本右边界二分搜索法)

    经典算法之右边界二分查找法(俗称基本右边界二分搜索法) 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 经典算法之右边界二分查找法(俗称基本右边界二分搜索法) 前言 一.什 ...

  7. 二分查找算法详解(经典二分和左右边界查找)

    目录 二分查找算法 1. 二分查找算法框架 2. 经典二分查找算法 问题1. 为什么while循环中使用<=号而不是用<号,右边区间right为什么要对数组大小减一? 问题2. 为什么 l ...

  8. 二分查找定边界(详细解析)

    二分查找定边界 学习二分查找的过程中发现经常因为边界定的不正确导致最终结果出错,写篇博客整理一下.以下所有数组都默认是按升序排列的.Leetcode上这篇Binary Search 101总结得非常好 ...

  9. 二分查找法+左右边界搜索

    原文参考:二分查找算法详解 思路 我相信对很多读者朋友来说,编写二分查找的算法代码属于玄学编程,虽然看起来很简单,就是会出错,要么会漏个等号,要么少加个 1. 不要气馁,因为二分查找其实并不简单.看看 ...

  10. 二分查找模板全面总结

    二分查找 二分法的引入 情形1 1.X的平方根 2.搜索旋转排序数组 情形2 1.第一个错误的版本 2.寻找峰值 3.寻找旋转排序数组中的最小值 情形3 在排序数组中查找第一个和最后一个位置 当遇到查 ...

最新文章

  1. 混合装置实现了24/7的能量收集和储存
  2. 面向对象编程的乐趣(TextBox.Text=)
  3. 【cs229-Lecture19】微分动态规划
  4. 用C#实现仿Ruby的XML Builder
  5. 广东工业大学计算机学院书记,计算机学院召开2018年工作总结大会
  6. python中x_python中round(x,[n])的使用
  7. qq2009显ip版怎么用_毛孔粗大怎么破?用对方法,轻松改善显皮肤嫩滑
  8. 玩家可以输入辅助指令_最后生还者 第二部辅助功能详解 盲人玩家也能玩
  9. 在Visual C++中用ADO进行数据库编程(中)
  10. 帮你找到了几份非公开的大数据报告,错过再无,手慢的人抓紧
  11. URL编码 java
  12. jqGrid的单字段查询
  13. 关于结合测试时,数据准备的一些注意点 (之开始篇:如何能更快,更好的准备测试数据)。
  14. Android——TextView属性XML详解
  15. vSphere虚拟机磁盘热扩容
  16. Java学习笔记之设计模式(7)单例模式
  17. [JDK1.8] Java-I/O流使用概述
  18. IDL实现TM遥感影像直方图统计(中值、均值、方差、众数及峰度系数计算)
  19. 数据库安全性存取控制机制
  20. OpenSSL 把cer证书链以及key文件生成keystore,tomcat https配置

热门文章

  1. 松翰单片机定时器c语言,松翰T0 定时器中断
  2. 比例风险(Cox)回归模型——Proportional hazards model
  3. ffmpeg用法及如何使用fluent-ffmpeg
  4. Python | Python也可以“举”
  5. html图片橡皮擦特效,原生制作的js涂鸦画板特效 可调画笔颜色|粗细|橡皮檫功
  6. 好文摘记——施一公教授:如何提高专业英语阅读水平
  7. windows远程linux桌面
  8. 计算机总是说该程序正在使用,另一个程序正在使用此文件,电脑程序正在使用此文件无法访问如何解决...
  9. ARM7-LPC213x(五)UART0 和 UART1
  10. mssql2000 mysql_MSSQL2000使用帮助