1、时间复杂度分析
T(n) = T(n/2) + O(1) = O(logn)
二分法:用O(1)时间将规模为n的问题变为n/2规模的问题。
2、二分法解决的问题
- 在一个数组中查找一个特定值,一般会是查找某个值(target)在该数组中第一次出现的位置,或者最后一次出现的位置,又或者是任何出现的位置。
- 问题可以一分为二的解决,前一半满足一个特点,后一半满足又一个特点,进而可缩小一半去寻找。九章算法中的原话是,二分法之OOOOXXXX问题。
- 问题规模总会一版一半的减少,从而达到O(log(n))的复杂度,也是真个二分的本质,这样的题不容易看出是二分问题。
另外,当你已经实现了复杂度为O(n)的算法,但有人还问你有没有更好的算法,那这个问题基本上就是让你用二分来实现,这属于用时间复杂度反推用什么算法。
3、算法模板
下面是九章算法课程中的一个二分法模板(C++实现):用于实现寻找第一个出现位置的问题。
/**
* 本参考程序由九章算法用户提供。版权所有,转发请注明出处。
* - 九章算法致力于帮助更多中国人找到好的工作,授课老师均来自硅谷和国内的一线大公司在职工程师。
* - 现有的求职课程包括:九章算法班 2020升级版,算法强化班,算法基础班,北美算法面试高频题班,Java 高级工程师 P6+ 小班课,面试软技能指导 - BQ / Resume / Project 2020版
* - Design类课程包括:系统设计 System Design,面向对象设计 OOD
* - 专题及项目类课程包括:动态规划专题班,Big Data - Spark 项目实战,Django 开发项目课
* - 更多详情请见官方网站:http://www.jiuzhang.com/?utm_source=code
*/
#include <vector>
using namespace std;
class Solution {
public:
/**
* @param array source array
* @param target target to search
* @return the first occurrence position of target
*/
int binarySearch(vector<int> &A, int target) {
if (A.size() == 0) {
return -1;
}
int start = 0;
int end = A.size() - 1;
int mid;
while (start + 1 < end) {
mid = start + (end - start) / 2;
if (A[mid] == target) {
end = mid;
} else if (A[mid] < target) {
start = mid;
} else if (A[mid] > target) {
end = mid;
}
}
if (A[start] == target) {
return start;
}
if (A[end] == target) {
return end;
}
return -1;
}
};
4、上面二分模板的说明
1、如果是寻找最后一个出现位置的问题的话,只需
(1)将上面
if (A[mid] == target) {
end = mid;
}
...
这个部分中if语句中的语句换为start = mid
(2)将程序中最后两个if语句互换一下顺序。
2、如果是寻找任意出现位置的话,用寻找第一次出现位置或寻找最后一次出现位置的模板都可以。
3、注意程序中while语句的判断条件是start + 1 < end
。
还有mid = start + (end - start) / 2
实际上是(start + end) / 2
的几乎等价写法,之所以这样写是为了防止start + end
太大会超过数值运算范围。