伟大的思想家庄子曾说过:「一尺之捶,日取其半,万世不竭」。这在纯数学理论上是成立的,我们可以在想象中将一尺无限分割为 1/2^n 尺。在实际生活中,我们却不可能将其无限细分,现在已发现的最小粒子单元是夸克,也就是说我们将「一尺之捶」最多分到一夸克便不可再分。限制我们继续细分的便是人类当前认知 有界。在算法世界,也有这样一种算法,它将一种条件一分为二,二分为四,达到可分的边界时停止。这就是二分算法。
来看一张动图了解一下:
适用情境二分算法适用范围很广,只要满足以下两个条件,就能使用二分算法。
- 单调
- 有界
单调的作用是让我们可以找到一个判断条件,每次分割后根据此判断条件缩小搜索范围;有界的作用是限制分割次数,在代码中体现就是根据边界终止循环。
我们在力扣题库中点击「二分查找」标签,显示如下:
粗略浏览可以发现,二分查找的题目中很多都带有「有序」、「排序」字样,这是一个很明显的单调条件,数组的长度是有限的,这是一个隐藏的有界条件。
固定写法二分法有固定的写法:
kotlin 实现
递归实现与非递归实现例题:力扣 35. 搜索插入位置 (点击链接查看题目)
这是一道典型的二分题目。根据题目描述我们可以分析出:
- 因为数组是有序的,所以 target 越大,答案越大,答案和 target 单调递增的关系
- 答案是有界的,在 [0, nums.size] 之间
根据二分法的固定写法,我们可以很快写出答案:
kotlin 实现
使用递归实现,需要将左边界和右边界作为参数传给递归函数,代码如下:
kotlin 实现
时间复杂度和空间复杂度分析
二分算法每次把搜索区域减少一半,所以时间复杂度是 O(log2n) 级的;
由于辅助变量是固定的,空间复杂度是 O(1).
后记一日,你到图书馆阅读书籍后,带了 n 本书出图书馆。这时,图书馆的报警器响起了「滴滴滴」的警报声!
正在埋头钻研《算法导论》的图书馆阿姨闻声走过来,说道:「呔!哪路小贼在此放肆,还不快将那本偷的书放下」。
于是你放下所有书,正准备一本本的试是哪一本书没有办理借阅手续,阿姨鄙夷的看你一眼,说道:「真笨,二分算法都不会。」
只见阿姨先将一半的书通过报警器,报警器响起了滴滴声。阿姨将这一半书再分一半,再次通过报警器,又响起了滴滴声……在 log2n 次比较之后,阿姨很快找到了报警的那一本书。阿姨得意地对你炫耀说:「看,这样多高效!」
然后,你在阿姨的带领下办理了那一本书的借阅手续,利用阿姨会二分算法,成功带走了剩余 n-1 本也没有办理借阅手续的书!
本文作者:Alpinist Wang
声明:本文归 “力扣” 版权所有,如需转载请联系。
文中部分图片来源于网络,为非商业用途使用,如有侵权联系删除。