一、基础概念

1、Sorted(单调递增or单调递减)

2、Bounded(存在上下界)

3、Accessible by index(能够通过索引访问,数组适合,but链表不适合)

二分查找是一种在每次比较之后将查找空间一分为二的算法。每次需要查找集合中的索引或元素时,都应该考虑二分查找。如果集合是无序的,我们可以总是在应用二分查找之前先对其进行排序。

二分查找一般由三个主要部分组成:

1、预处理--如果有集合未排序,则进行排序。

2、二分查找--使用循环或递归在每次比较后将查找空间划分为两半

3、后处理--在剩余空间中确定可行的候选者

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

示例 1:

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

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2 输出: -1 解释: 2 不存在 nums 中因此返回 -1

提示:

1、你可以假设 nums 中的所有元素是不重复的。

2、n 将在 [1, 10000]之间。

3、nums 的每个元素都将在 [-9999, 9999]之间。

step01: 设定初始值 left和 right:

程序员的数学二分查找法(大厂高级程序员必备算法)(1)

step02: 设定中间指针 mid = left (right-left)/2:

程序员的数学二分查找法(大厂高级程序员必备算法)(2)

step03:

程序员的数学二分查找法(大厂高级程序员必备算法)(3)

step04:

程序员的数学二分查找法(大厂高级程序员必备算法)(4)

step05:

程序员的数学二分查找法(大厂高级程序员必备算法)(5)

step06:

程序员的数学二分查找法(大厂高级程序员必备算法)(6)

step07:

程序员的数学二分查找法(大厂高级程序员必备算法)(7)

二、通用模版

2.1 模版一

var binarySeach(nums,target){ if(nums == null|| nums.length ==0){ return -1; } let left =0,right=nums.length- 1; //初始条件 while(left<=right){ //终止条件 left>right let mid = Math.floor(left (right-left)/2); if(nums[mid] == target){ return mid; } else if(nums[mid]<target){ left = mid 1; //向右查找 }else{ right = mid - 1; //向左查找 } } return -1; }

关键属性:

2.2 模版二

var binarySeach(nums,target){ if(nums == null|| nums.length ==0){ return -1; } let left =0,right=nums.length; //初始条件 while(left<right){ //终止条件 left>=right let mid = Math.floor(left (right-left)/2); //阻止(left right)溢出 if(nums[mid] == target){ return mid; } else if(nums[mid]<target){ left = mid 1; //向右查找 }else{ right = mid; //向左查找 } } if(left !=nums.length && nums[left] == target) return left; return -1; }

模版二:是二分查找的高级模板。它用于查找需要访问数组中当前索引及其直接右邻居索引的元素或条件。

关键属性:

2.3 模版三

var binarySeach(nums,target){ if(nums == null|| nums.length ==0){ return -1; } let left =0,right=nums.length-1; //初始条件 while(left 1 < right){ //终止条件 left 1 == right let mid = Math.floor(left (right-left)/2); //阻止(left right)溢出 if(nums[mid] == target){ return mid; } else if(nums[mid]<target){ left = mid; //向右查找 }else{ right = mid; //向左查找 } } if(nums[left] == target) return left; if(nums[right] == target) return right; return -1; }

模版3是二分法查找的另一种独特形式。 它用于搜索需要访问当前索引及其在数组中的直接左右邻居索引的元素或条件。

关键属性:

2.4、模版分析:

程序员的数学二分查找法(大厂高级程序员必备算法)(8)

这三个模版的不同之处在于:

其中模版一和模版三是最常用的, 几乎所有二分查找问题都可以用其中之一亲送实现。 模版二更高级一些, 用于解决某些类型的问题。

这 3 个模板中的每一个都提供了一个特定的用例:

模板 1 (left <= right)

模板 2 (left < right)

模板 3 (left 1 < right)

三、复杂度计算

3.1、时间复杂度

O(log n) :

因为二分查找是通过对查找空间中间的值应用一个条件来操作的,并因此将查找空间折半,在更糟糕的情况下,我们将不得不进行O(log n) 次比较, 其中n是集合中元素的数目。

为什么是log n?

第一次: n/2 第二次: n/2^2 第三次: n/2^3 ... 第k次: n/2^k

程序员的数学二分查找法(大厂高级程序员必备算法)(9)

程序员的数学二分查找法(大厂高级程序员必备算法)(10)

3.2、空间复杂度

O(1)

虽然二分查找确实需要跟踪 3 个指标,但迭代解决方案通常不需要任何其他额外空间,并且可以直接应用于集合本身,因此需要 O(1) 或常量空间。

四、二分查找的应用

把所有潜在的问题都用类似“数组二分查找”的方式把代码遍历一遍,不断缩小问题的范围,最终找到问题原因。

通过二分法,我们可以快速缩小问题范围,这样一来调试的效率也就上去了。

二分查找相关系列题:

程序员的数学二分查找法(大厂高级程序员必备算法)(11)

,