二分查找算法尽管简单,但面试中也比較常见。经经常使用来在有序的数列查找某个特定的位置。在LeetCode用到此算法的主要题目有:

Search
Insert Position


Search
for a Range


Sqrt(x)

Search
a 2D Matrix


Search
in Rotated Sorted Array


Search
in Rotated Sorted Array II




这类题目基本能够分为例如以下四种题型:

1. Search
Insert Position
Search
for a Range
是考察二分查找的基本使用方法。基本思路是每次取中间,假设等于目标即返回,否则依据大小关系切去一半,因此时间复杂度是O(logn),空间复杂度O(1)。

Search
Insert Position
为例,其关键代码写法例如以下:

    int l = 0;
int r = A.length-1;
while(l<=r)
{
int mid = (l+r)/2;
if(A[mid]==target)
return mid;
if(A[mid]<target)
l = mid+1;
else
r = mid-1;
}
return l;

这样当循环停下来时,假设不是正好找到target,l指向的元素恰好大于target。r指向的元素恰好小于target,这里l和r可能越界。只是假设越界就说明大于(小于)target而且是最大(最小)。Search
for a Range
这道题能更好的解释这一点。

其思路是先用二分查找找到当中一个target。然后再往左右找到target的边缘。我们主要看找边缘(往后找)的代码:

    int newL = m;
int newR = A.length-1;
while(newL<=newR)
{
int newM=(newL+newR)/2;
if(A[newM]==target)
{
newL = newM+1;
}
else
{
newR = newM-1;
}
}
res[1]=newR;
我们的目标是在后面找到target的右边界。由于左边界已经等于target,所以推断条件是相等则向右看,大于则向左看,依据上面说的,循环停下来时。l指向的元素应该恰好大于target。r指向的元素应该等于target。所以此时的r正是我们想要的。向前找边缘也同理。

2. Sqrt(x)是数值处理的题目,但同一时候也能够用二分查找的思想来解决。由于我们知道结果的范围,取定左界和右界,然后每次砍掉不满足条件的一半,直到左界和右界相遇。算法的时间复杂度是O(logx),空间复杂度是O(1)。这里相同是考察二分查找的基本使用方法。代码例如以下:
public int sqrt(int x) {
if(x<0) return -1;
if(x==0) return 0;
int l=1;
int r=x/2+1;
while(l<=r)
{
int m = (l+r)/2;
if(m<=x/m && x/(m+1)<m+1)
return m;
if(x/m<m)
{
r = m-1;
}
else
{
l = m+1;
}
}
return 0;
}

这里要注意,这里推断相等的条件不是简单的 m == x/m, 而是 m<=x/m && x/(m+1)<m+1, 这是由于输出是整型。sqrt(14)=3 但 3 != 14/3. 所以我们须要一个范围框住结果。另外依据二分查找算法的特性,假设不能正好m==x/m停下,那么r指向的数字将正好是结果取整的值。

所以我们也能够这样写:

public int sqrt(int x) {
if(x<0) return -1;
if(x==0) return 0;
int l=1;
int r=x/2+1;
while(l<=r)
{
int m = (l+r)/2;
if(m==x/m )
return m;
if(x/m<m)
{
r = m-1;
}
else
{
l = m+1;
}
}
return r;
}
3. Search a 2D Matrix是二分查找算法的多维应用,通过观察不难发现。输入的矩阵行内有序而且行间有序,所以查找仅仅须要先按行查找,定位出在哪一行之后再进行列查找就可以,两次二分查找,时间复杂度是O(logm+logn)。空间上仅仅需两个辅助变量。因而是O(1)。这里不再赘述。



4. Search in Rotated Sorted ArraySearch
in Rotated Sorted Array II
算是二分查找算法的一个变体。

Search in Rotated Sorted Array中,乍一看感觉数组已经不是有序的了。也就无法用二分查找算法,但细致分析一下会发现,由于仅仅rotate了一次,如果二分一下,总有一半是有序的,并且和还有一半无区间重叠,我们仅仅须要检查有序的一半的前后两个元素就能够确定target可能在哪一半。详细来说,如果数组是A,每次左边缘为l,右边缘为r。还有中间位置是m。

在每次迭代中,分三种情况:

(1)假设target==A[m],那么m就是我们要的结果,直接返回;

(2)假设A[m]<A[r]。那么说明从m到r一定是有序的(没有受到rotate的影响),那么我们仅仅须要推断target是不是在m到r之间,假设是则把左边缘移到m+1,否则就target在还有一半,即把右边缘移到m-1。

(3)假设A[m]>=A[r]。那么说明从l到m一定是有序的,相同仅仅须要推断target是否在这个范围内,对应的移动边缘就可以。

依据以上方法,每次我们都能够切掉一半的数据。所以算法的时间复杂度是O(logn),空间复杂度是O(1)。

Search in Rotated Sorted Array II中array有反复元素,依照刚刚的思路,二分之后尽管一半是有序的,但我们会遇到中间和边缘相等的情况,我们就丢失了哪边有序的信息。由于哪边都有可能是有序的结果。如果原数组是{1,2,3,3,3,3,3}。那么旋转之后有可能是{3,3,3,3,3,1,2},或者{3,1,2,3,3,3,3},这种我们推断左边缘和中心的时候都是3,如果我们要寻找1或者2,我们并不知道应该跳向哪一半。解决的办法仅仅能是对边缘移动一步。直到边缘和中间不在相等或者相遇,这就导致了会有不能切去一半的可能。

所以最坏情况(比方所有都是一个元素。或者仅仅有一个元素不同于其它元素,而他就在最后一个)就会出现每次移动一步,总共是n步,算法的时间复杂度变成O(n)。



整体来说。二分查找算法理解起来并不算难。但在实际面试的过程中可能会出现各种变体,怎样灵活的运用才是制胜的关键。

我们要抓住“有序”的特点。一旦发现输入有“有序”的特点,我们就能够考虑能否够运用二分查找算法来解决该问题。

LeetCode总结--二分查找篇的更多相关文章

  1. LeetCode 704. 二分查找(Binary Search)

    704. 二分查找 704. Binary Search 题目描述 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target,写一个函数搜索 nums 中的 target,如果 ...

  2. 【LeetCode】二分查找

    给一个升序数组,找到目标值在数组中的起始和结束位置,时间复杂度为 O(log n). e.g. 给定数组 [5, 7, 7, 8, 8, 10] 和目标值 8,返回 [3, 4].若目标值不在数组中, ...

  3. Java实现 LeetCode 704 二分查找(二分法)

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

  4. LeetCode 704.二分查找(C++)

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

  5. LeetCode 704. 二分查找

    题目链接:https://leetcode-cn.com/problems/binary-search/ 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函 ...

  6. leetcode中二分查找的具体应用

    给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值,返回 [ ...

  7. C#LeetCode刷题-二分查找​​​​​​​

    二分查找篇 # 题名 刷题 通过率 难度 4 两个排序数组的中位数 C#LeetCode刷题之#4-两个排序数组的中位数(Median of Two Sorted Arrays)-该题未达最优解 30 ...

  8. 分治算法(二分查找)、STL函数库的应用第五弹——二分函数

    分治算法:二分查找!昨天刚说不写算法了,但是突然想起来没写过分治算法的博客,所以强迫症的我…… STL函数库第五弹——二分函数lower_bound().upper_bound().binary_se ...

  9. LeetCode刷题总结-二分查找和贪心法篇

    本文介绍LeetCode上有关二分查找和贪心法的算法题,推荐刷题总数为16道.具体考点归纳如下: 一.二分查找 1.数学问题 题号:29. 两数相除,难度中等 题号:668. 乘法表中第k小的数,难度 ...

随机推荐

  1. Spring与Struts2集成开发

    Struts2和Spring都是不错的开源框架,Spring与Struts2集成开发,把二者结合在一起使用,开发效果更佳,效率杠杠的.下面介绍一下如何将Spring与Struts2集成在一起开发.分七 ...

  2. Masonry 原理与使用说明

    原理: 1)约束生成:MASConstraintMaker: 2)缺省补齐: - (void)setSecondViewAttribute:(id)secondViewAttribute { if ( ...

  3. node遍历给定目录下特定文件,内容合并到一个文件

    遍历目录用了fs.readdir这个异步方法,得到当前目录下所有的文件和目录的一个数组.然后判断: if文件,并且后缀符合设定的规则(本文例子是符合后缀ts,js)直接用同步方法写入, if目录,继续 ...

  4. vue-quill-editor富文本焦点问题

    vue-quill-editor富文本渲染完成自动获取焦点,问题在于数据请求完成,富文本内容发生变化从而自动获取焦点 mounted() { this.$refs.myQuillEditor.quil ...

  5. 扒一扒PROMISE的原理,大家不要怕!

    在前端的日常工作中,回调函数(callback)应该是见怪不怪了,但是当回调函数遇上了异步(async),这就令人发指了.那么异步是什么意思呢,简单地说就是不等你执行完,就先执行下方的代码了. 举个

  6. 12Cookie、Session

    12Cookie.Session-2018/07/24 1.保存会话数据 cookie客户端技术,把每个用户的数据以cookie的形式写给用户各自的浏览器 HttpSession服务端技术,服务器运行 ...

  7. centos 7桌面和命令行转行

    CentOS7图形界面与命令行界面(终端)切换(1)CentOS7 在图形界面进入dos界面 :ctrl+alt+F6 dos界面进入图形界面:ctrl+alt+F2 本机用的这个命令: (2)Cen ...

  8. python实现字符串转换整数

    实现一个函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止. 当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续 ...

  9. virtualenv与virtualenvwrapper

    一.Linux下安装.配置virtualenv pip3 install virtualenv # 创建虚拟环境env1 virtualenv env1 --no-site-packages --py ...

  10. 洛谷 2777 [AHOI2016初中组]自行车比赛

    [题解] 为了让某个选手能够获得总分第一,就让他最后一天的得分是n,并且让别的选手的得分的最大值尽量小.于是我们先把目前积分排序,并且让他们最后一天的排名刚好与积分排名相反.即某个积分排名为X的人最后 ...