應用:
找一個數(shù)組中的局部最小值蜓肆,任意一個都行擎析。(這個就不要求二分必須有序)
局部最小值:如果arr[0]<arr[1] 那0位置就是局部最小值悄雅,如果arr[arr.length-1]<arr[length-2]那么arr.length-1就是局部最小值逢渔,如果arr[m]<arr[m+1]且小于arr[m-1]那么m就是局部最小值
思路:
如果局部最小值不在最左邊和最右邊校赤,那么說明肯定在中間躁锡,如下圖所示
image.png
如圖所示午绳,m極為局部最小值,當m比m+1和m-1都大的時候映之,找那邊都行
這里注意一下整體看拦焚,最開始是下降趨勢arr[0]<arr[1] ,最后是上升趨勢arr[arr.length-1]<arr[length-2]杠输,所以局部最小在中間赎败,既然在最后有上升趨勢即arr[arr.length-1]<arr[length-2],所以中間肯定就有個開始上升趨勢的地方蠢甲,和之前下降趨勢一結合就肯定有局部最小僵刮,類似一個先下降后上升的一元二次函數(shù),在最低點就是局部最小唄鹦牛。
代碼:
public static int getLessIndex(int[] arr) {
if (arr == null || arr.length == 0) {
return -1; // no exist
}
if (arr.length == 1 || arr[0] < arr[1]) {
return 0;
}
if (arr[arr.length - 1] < arr[arr.length - 2]) {
return arr.length - 1;
}
int left = 1;
int right = arr.length - 2;
int mid = 0;
while (left < right) {
mid = (left + right) / 2;
if (arr[mid] > arr[mid - 1]) {
right = mid - 1;
} else if (arr[mid] > arr[mid + 1]) {
left = mid + 1;
} else {
return mid;
}
}
return left;
}
public static void printArray(int[] arr) {
for (int i = 0; i != arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr = { 6, 5, 3, 4, 6, 7, 8 };
printArray(arr);
int index = getLessIndex(arr);
System.out.println("index: " + index + ", value: " + arr[index]);
}
注意:
在取mid時搞糕,mid = right - ((right-left)>>1) 和left + ((right - left)>>1)不一樣,第一種情況不行曼追,因為比如right=5窍仰,left=2,mid=4礼殊,但實際mid=3