二分法?
先看一个很有意思的段子
有一天小明到图书馆借了 N 本书,出图书馆的时候,警报响了,于是保安把小明拦下,要检查一下哪本书没有登记出借。小明正准备把每一本书在报警器下过一下,以找出引发警报的书,但是保安露出不屑的眼神:你连二分查找都不会吗?于是保安把书分成两堆,让第一堆过一下报警器,报警器响;于是再把这堆书分成两堆…… 最终,检测了 logN 次之后,保安成功的找到了那本引起警报的书,露出了得意和嘲讽的笑容。于是小明背着剩下的书走了。 从此,图书馆丢了 N - 1 本书。
相信大家从小学的时候就已经接触过了很多关于二分法的题目了,对于二分法的一些思想这里博主就不展开说了
那么今天博主就从编程算法的角度来讨论,如果遇到二分法的题目该这么解答。
例题
首先我们要知道使用二分法是有一个条件的,那就是必须是顺序排序的,这个我们要注意。
public static void main(String[] args) {
int[] nums = {-1, 0, 3, 5, 9, 12};
int target = 9;
int n = 9;
//调用如下方法
//数组查找
int i = search(nums,target);
System.out.println(i+1);
//错误版本号
int j = search2(n);
System.out.println("错误的版本号为:"+j);
//输出插入位置
int k = search3(nums, target);
System.out.println("插入位置是"+(k+1));
}
数组查找
给定一个数组和一个目标值,需要找到这个目标值在数组中的位置,并打印,如果没有则输出-1
private static int search1(int[] nums, int target) {
// 定义数组的左右指针
int left = 0, right = nums.length - 1;
// 判断条件:当左指针大于右指针的时候,我们默认循环结束
while (left < right) {
// 定义一个数用接收二分法所选的位置 = 左指针位置+剩余长度的一半
int mid = left + (right - left) / 2;
// 判断条件
if (nums[mid] > target) {//如果所选的这个数大于目标值,那么目标值在它的左边
// 这个时候就需要调整右指针
right = mid - 1;//需要注意数组下标越界
} else if (nums[mid] < target) {//反之亦然
left = mid + 1;
} else {
return mid;
}
}
return -2;
}
错误版本号
你是产品经理,目前正在带领一个团队开发新的产品。假设你有 n 个版本 [1, 2, …, n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
private static int search2(int n) {
// 在这个代码中我们只需要定义一个左指针
int left = 0;
// 判断条件依然是当左边界大于右边界时
while (left < n) {
int mid = left + (n - left) / 2;
// 在这个题中,给定的条件是需要判断是是否为该版本为错误版本
if (isBadVersion(mid)) {
// 所以我们可以直接将这个值赋值给n
n = mid;
} else {
left = mid + 1;
}
}
return n;
}
插入位置
这个题和上面的数组位置中的位置查找有些不同的是,如果这个位置的值不存在那么就把这个位置的索引给返回。
private static int search3(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
right = mid - 1;
}else{
left = mid + 1;
}
}
//最后返回的是他们的位置
return left;
}
好了详细就举这三道例题了,二分法的介绍就这样吧,后续博主还会出关于算法题目详解,喜欢的就留下三连吧,我们下片博客见。