找出>=num的有序区间的最左值索引
例:找出有序数组arr中>=8的数中的最左值索引。
有如下数组arr:≥8的最左值索引为5(值为11)
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
value | 1 | 2 | 2 | 3 | 6 | 11 | 11 | 12 |
思路:将区间的中间值mid与给定值num作比较,用一个变量index记录满足条件的索引所在位置。有如下两种情况:
1.当mid>=num时,满足条件,故将index指向mid;此时继续向mid左侧区间搜寻,以查找满足条件的最左侧值。
2.当mid<num时, 不满足条件,故答案应处于mid右侧区间,此时向mid右侧区间搜寻。
public static int MostLeftNoLessNumIndex(int[] arr,int num) {
//若数组为空,返回值-1;
if (arr==null || arr.length==0) {
return -1;
}
int ans = -1;
//用L和R分别记录指向区间的最左和最右;
int L = 0;
int R = arr.length-1;
while (L <= R) {
//二分法;取区间中点值并进行条件判断;
int mid = L + (R-L)/2;
//满足条件,向左侧搜寻;
if (arr[mid] >= num) {
ans = mid;
R = mid - 1;
} else {
L = mid + 1;//不满足条件,向右侧搜寻;
}
}
return ans;
}
类似地,可以找出<=num的最右值。
二分法找出数组 (任意相邻值不等) 的局部最小值
例:用二分法找出一个满足条件的局部最小值
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
value | 26 | 15 | 14 | 9 | 13 | 16 | 3 | 13 |
思路:
1.先判断处在数组第一个和最后一个的值是否为局部最小,若局部最小,直接返回。
2.若第一步没有找出局部最小,则利用二分法从中间查找 (区间的最左侧呈下降趋势,最右侧呈上升趋势,故中间必定至少存在一个局部最小值)。
public static int oneMinIndex(int[] arr) {
if (arr==null || arr.length==0) {
return -1;
}
int N = arr.length;
int ans = -1;
if (N==1) {
return 0;
}
//先判断边界处是否满足局部最小条件;
if (arr[0] < arr[1]) {
return 0;
}
if (arr[N-1] < arr[N-2]) {
return N-1;
}
int L = 0;
int R = N-1;
while (L <= R) {
int mid = L+ (R-L)/2;
//若mid同时小于左右两侧的值,则满足条件直接返回;
if (arr[mid] < arr[mid-1] && arr[mid] < arr[mid+1]) {
ans = mid;
break;
}
//若mid>左侧值,则左边至少存在一个局部最小值;
else if (arr[mid] > arr[mid-1]) {
//先判断边界是否满足局部最小;
if (arr[mid-1] < arr[mid-2]) {
return mid-1;
}
//若边界不满足,则向左侧搜寻
R = mid - 1;
}
//若mid>右侧值,则右边至少存在一个局部最小值;
else if (arr[mid] > arr[mid+1]) {
//先判断边界是否满足局部最小;
if (arr[mid+1] > arr[mid+2]) {
return mid+1;
}
//若边界不满足,则向右侧搜寻;
L = mid + 1;
}
}
return ans;
}
由此找出的第一个局部最小值为9,其索引为3。