题目:
查询一个数组的任意一个局部最小值(如果第0个元素 < 第1个元素,0就是局部最小 , 第length - 1个元素 < 第length - 2元素,length - 1 就是局部最小),中间部分要满足局部最小值需要该位置上的值既小于左边元素值也小于右边元素值,。其中,数组无序且相邻两个数一定不相等。
分析:
先去判断左右两个边界是否为局部最小, 如果是则输出其下标0或者arr.length-1 如果两个边界全部不是局部最小值, 就采用二分法去查找中间部分的局部最小值:
- 首先要明确两端不是局部最小值就说明中间部分一定有局部最小值(因为arr[0]->arr[1]是递减, arr[length-2]->arr[length-1]是递增, 中间部分就至少有一个拐点)
- 所以可以使用二分法, 假设arr[mid1]不是局部最小点, 说明arr[mid1-1]<arr[mid]或者arr[mid]>arr[mid+1],也可能arr[mid1]是局部最大点:
如果arr[mid1]<arr[mid1+1], 就在0和mid-1之间继续二分
如果arr[mid1-1]>arr[mid1], 就在mid+1和arr.length-1之间继续二分
如果是局部最大点,可以任意选择在哪边进行二分
代码实现:
public static int searchMin(int[] arr) {
if (arr == null) {
return -1;
}
if (arr.length == 1) {
return 0;
}
if (arr[0] < arr[1]) { // 左端属于局部最小值
return 0;
}
if (arr[arr.length - 1] < arr[arr.length - 2]) { // 右端属于局部最小值
return arr.length - 1;
}
int L = 0, R = arr.length - 1;
while (L <= R) {
int mid = L + ((R - L) >> 1);
if (mid == 0) {
return mid + 1;
}
if (arr[mid] < arr[mid - 1] && arr[mid] < arr[mid + 1]) { //mid位置上的值小于左面且小于右面
return mid;
} else if (arr[mid] < arr[mid - 1]) { //mid位置上的值小于左边且大于右边
L = mid + 1;
} else { //mid位置上的值大于左边且小于右边
R = mid - 1;
}
}
return -1;
}