二分法又可以被称为二分查找法,它描述了在有序集合中搜索特定值的过程。广义的二分查找是将问题的规模尽可能的缩小到原有的一半。
百度百科的讲解
其实 二分法 也不一定只适用于 排好序的数据 比如下面的查找局部最小值题目
二分法 时间复杂度为O(logN)
题目一:
从一个有序数组中找到特定的值 如果有则返回true 没则返回false
public static boolean dichotomy(int[] arrs,int target) {
//如果数组长度小于1 或 数组为空则返回false
if(arrs==null | arrs.length<1) {
return false;
}
int mid = arrs.length/2;
int left=0,right = arrs.length-1;
while(left<=right) {
if(arrs[mid] == target) {
System.out.println(target +"的位置是:"+mid);
return true;
}else if(arrs[mid]>target) { //证明目标值在mid的左边
right = mid-1;
mid = (left+right)/2;
}else if(arrs[mid]<target){ //证明目标值在mid的右边
left = mid+1;
mid = (left+right)/2;
}
}
//证明找不到目标值
System.out.println("数组中无此 "+target+" 元素");
return false;
}
题目二:
在一个有序数组中 找到>=某个数的最左侧的位置 (此程序一定是二分到结束的)
public static int dichotomyLeftIndex(int[] arrs,int target) {
//如果数组长度小于1 或 数组为空 则返回-1 表示找不到
if(arrs == null | arrs.length <1 ) {
return -1;
}
int mid = arrs.length/2;
int left = 0,right = arrs.length-1;
int finalIndex = -1;
while(left<=right) {
if(arrs[mid] >= target) { //左侧可能还有答案 继续二分 先记录当前位置
finalIndex = mid;
right = mid -1;
mid = (left+right)/2;
}else { // 答案在右侧
left = mid+1;
mid = (left+right)/2;
}
}
return finalIndex;
}
题目三:
在一个有序数组中 找到<=某个数的最右侧的位置 (此程序一定是二分到结束的)
public static int dichotomyRightIndex(int[] arrs,int target) {
//如果数组长度小于1 或 数组为空 则返回-1 表示找不到
if(arrs == null | arrs.length <1 ) {
return -1;
}
int mid = arrs.length/2;
int left = 0,right = arrs.length-1;
int finalIndex = -1;
while(left<=right) {
if(arrs[mid] <= target) { //右侧可能还有答案 继续二分 先记录当前位置
finalIndex = mid;
left = mid+1;
mid = (left+right)/2;
}else { // 答案在左侧
right = mid -1;
mid = (left+right)/2;
}
}
return finalIndex;
}
题目四:
局部最小值问题:在一个无序数组中 已知相邻两个数一定不相等
如今要找到这样一个值
如果这个数在最左边 ( 索引为0 ) 且索引为1的值一定大于索引为0的值,这样索引为0的值才能称为局部最小值
如果这个数在最右边 ( 索引为len-1 ) 且索引为 len-2 的值一定大于索引为len-1的值,这样索引为len -1的值才能称为局部最小值
如果这个数在中间 ( 索引为i ) 且索引为 i-1 的值一定大于索引为 i的值,索引为 i+1的值一定大于索引为 i的值,这样索引为i的值才能称为局部最小值
时间复杂度变成O(logN)
public static int searchLocalMin(int[] arrs) {
//如果数组长度小于1 或 数组为空 则返回-1
if(arrs == null | arrs.length < 1) {
return -1;
}
//局部最小值 在头部情况 或 数组只有一个数
if(arrs[0]<arrs[1] || arrs.length==1) {
return 0;
}
//局部最小值 在尾部情况
if(arrs[arrs.length-1]<arrs[arrs.length-2]) {
return arrs.length-1;
}
int mid = arrs.length/2;
int left = 1,right = arrs.length-2;
while(left < right) {
System.out.println("mid:"+mid);
if(arrs[mid]>arrs[mid-1]) { //左侧必有局部最小值
right = mid - 1;
}else if(arrs[mid]>arrs[mid+1]) { //右侧必有局部最小值
left = mid + 1;
}else {
//此值就是局部最小值
return mid;
}
mid = (left+right)/2;
}
//这里返回left 是因为while中条件没有等于 如果while条件有等于 这里返回-1
return left;
}