1.基本二分查找:
一个有序数组arr[],使用二分查找其中的num,返回Boolean值。
思路:三个索引变量,L、R、mid,其中mid=(L+R)/2,循环条件while(L<=R),if条件比较arr[mid]与num的关系,进而将mid(+1/-1)赋值给L或R值,逐步缩小查询范围,直至arr[mid]= =num。
具体代码如下:
public static boolean find(int[] arr, int num) {
//边界条件
if (arr == null || arr.length == 0) {
return false;
}
//二分查询逻辑
int L = 0;
int R = arr.length - 1;
int mid = 0;
while (L <= R) {
mid = (L + R) / 2;
if (arr[mid] < num) {
L = mid + 1;
} else if (arr[mid] > num) {
R = mid - 1;
} else if (arr[mid] == num) {
return true;
}
}
return false;
}
2.二分查找扩展:
(1)查找某数最左位置
一个有序数组arr[],使用二分查找其中>=num最左的位置,返回索引值。
例:有序数组arr[0,1,2,2,3,4,5],其中>=2最左位置的索引为2。
思路:三个索引变量,L、R、mid,其中mid=(L+R)/2,一个记录索引值变量index,循环条件while(L<=R)。利用二分法更新查询范围,且只有当arr[mid]的值在>=num内范围,才更新索引值index=mid,使index逐渐逼近>=num最左的位置。
具体代码如下:
public static int findIndex(int [] arr,int num){
//边界条件
if (arr==null||arr.length==0){
return -1;
}
//二分查询逻辑
int L=0;
int R= arr.length-1;
int mid=0;
int index=-1;
while (L<=R){
mid=(L+R)/2;
if (arr[mid]>=num){
R=mid-1;
index=mid;
}else if (arr[mid]<num){
L=mid+1;
}
}
return index;
}
(2)数组局部最小
局部最小定义:当arr[0]<arr[1],arr[0]为局部最小;当arr[n-1]>arr[n]时(n=arr.length-1),arr[n]为局部最小;当arr[i-1]>arr[i]<arr[i+],arr[i]为局部最小。
需求:查找一个数组的局部最小,并返回;该数组无序,且相邻两数不可相等。
思路:先寻找前两种定义是否满足,若前两种定义不满足,则根据第三种定义查找局部最小。第三种定义查找局部最小时,取中间mid索引值,并进行循环条件判断,当mid-1>mid<mid+1时,即满足定义返回局部最小;若mid>mid-1,则在mid-1与0间必然存在局部最小,利用二分法缩小范围;若mid>mid+1则在mid+1与n之间必有最小值,利用二分法缩小范围。
mid-1与0间或mid+1与n之间必然存在局部最小的原理图如下:
即根据局部最小定义,最小值必然存在于递减方向。
具体代码如下:
public static int findMin(int[] arr) {
//最大索引号
int n = arr.length - 1;
//定义起始二分左右索引
int L = 0;
int R = n;
//边界条件
if (arr.length == 1 || arr == null) {
return -1;
}
//定义1判断
if (arr[0] < arr[1]) {
return arr[0];
}
//定义2判断
if (arr[n] < arr[n - 1]) {
return arr[n];
}
//定义1、2都不满足,二分法循环条件判断
int mid = 0;
while (L < R) {
//二分中间索引
mid = (L + R) / 2;
//条件判断
if (arr[mid - 1] > arr[mid] && arr[mid] < arr[mid + 1]) {
return arr[mid];
} else if (arr[mid - 1] < arr[mid]) {
R = mid - 1;
} else if (arr[mid+1] < arr[mid]) {
L=mid+1;
}
}
return -1;
}