我理解的二分搜索
Posted wory
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我理解的二分搜索相关的知识,希望对你有一定的参考价值。
今天刷leetcode的时候做了好几道和二分搜索(BS)相关的题,发现主要的问题有两个:有的题不是很直观的就知道用BS;BS用起来corner case处理不好。下面我就来总结一下BS的用法和代码模版。
1. 什么时候可以用BS算法?
这里先引用下大牛Knuth的话——“Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly tricky ...”。意思是说BS算法听上去很直观,但是细节可能非常棘手。他在其著作《计算机程序设计的艺术 第3卷:排序和查找》中写到“二分查找法的思想在 1946 年就被提出来了。但是第 1 个没有 Bug 的二分查找法在 1962 年才出现。”可见BS算法也并不是我们想的那么容易。那什么时候可以用二分算法呢?通常问题中出现有序数组的时候我们通常会想到能不能用BS求解,这种惯性思维导致我们误以为“有序”是应用BS的必要条件,其实不然,比方我们同样可以用BS算法在数组[4, 3, 2, 1, 5, 6, 7, 8, 9]中准确找到5这个元素。5是一个partition,它把数组分成了小于5和大于5两个部分,如果某个元素大于5,一定有5在该元素的左边,如果小于5,一定有5在该元素的右边。这么看来BS就是一个特殊的排除法,专门用来找这个partition的!!!我们用形式语言简单定义一下(可能不是很严谨)。
有区间[start, end),以及有定义在这个区间上的映射f和一个条件A,假设有一个属于[start, end)上的点x,使得x左边的点对于映射f满足条件A,x右边的点对于映射不满足条件A(这里反过来也没问题,至于x自身满不满足条件A都可以),如果知道了这个条件A和f,就可以通过二分来找到点x。
原来二分就是用来找partition的,在有序数组中,每个点都是partition,因此可以用来查找。而在例子[4, 3, 2, 1, 5, 6, 7, 8, 9]中,partition只有5元素一个。
2. BS算法模版
BS的循环判断条件有的人喜欢写成left<=right,最后返回的时候就要考虑是返回left还是right,我不习惯这么写,觉得还是用left<right更符合计算机常识,这里left和right初始指对应[start, end)两个端点。
1 def BS_template(): 2 left, right = start, end 3 while left < right: 4 # C++ 用 mid = left + ((right - left) >> 1), 否则可能加法溢出 5 mid = (left + right) >> 1 6 if f(mid) match A: 7 right = mid 8 else: 9 left = mid + 1 10 return left
以上是关于我理解的二分搜索的主要内容,如果未能解决你的问题,请参考以下文章