什麼是左側(右側)邊界二分查找
上一篇博客,細訴了二分查找的細節和實現邏輯,當時存在侷限性,比如有一個數組int[] arr={1,2,2,2,3,5,7},目標num=2,返回索引是3,假如需要返回最左側索引(1)或最右側的索引(3),這樣的話普通二分查找是無法實現的
來一個左側邊界二分查找:
public static int getTwoNum5(int[] arr, int num) {
int left = 0;
int right = arr.length;
// while(left < right) 終止的條件是 left == right,此時搜索區間 [left, left)
// 爲空,所以可以正確終止
while (left < right) {
int index = (left + right) / 2;
System.out.println("當前索引位置:" + index + "索引值爲:" + arr[index]);
if (num == arr[index]) {
// 當查詢索引index查詢到標的值,不立即返回而是縮小right邊界[left,index]繼續往左側邊界查找
right = index;
} else if (arr[index] > num) {
// 初始二分索引值比標的num值大,查詢範圍[0,index]
right = index;
} else if (arr[index] < num) {
// 初始二分索引值比標的num小,查詢範圍[index+1,right)
left = index + 1;
}
}
return arr[left] == num ? left : -1;
}
細節問題:
-
爲什麼right=arr.length而不是arr.length-1
答:因爲搜索區間是左閉右開的,當arr[index]=num或者arr[index]>num時,循環範圍都是[left,index),這樣不斷搜索區間靠左查詢。 -
爲什麼while的循環條件是<而不是<=
答:當查詢最左側或者最右側邊界成立時即arr[index]=num,右側邊界會賦值爲right=index,如果循環結束條件leth<=right,最左側情況(0,0)或最右側情況(arr.lenght-1,arr.lenght-1)出現死循環無法改出。 -
爲什麼right=index;left=index+1
答:是爲了切割二分查詢後左右兩側邊界,當初次二分索引查詢值比標的num大時,查詢範圍切割爲[left,index),當比標的num小時,查詢範圍切割爲[index+1,right)。 -
爲什麼numarr[index]時right=index
答:當查詢索引index查詢到標的值num時,不立即返回而是縮小right邊界[left,index]繼續往左側邊界查找,可以一直查到最左側,如果出現[index+1,right],當numarr[index],則查詢直接返回 -
如果是右側邊界的二分搜索
答:只需要在num==arr[index]成立時,不立即返回而是縮小left邊界,賦值left=index+1繼續向右側查找[index+1,right].