[英]Using a Variant of BinarySearch to Find the Maximum in a Bitonic Array
這是我的代碼,其中a
是要找到最大值的數組(每個元素都是不同的)。 從我的角度來看,如果a[mid]
小於a[mid-1]
那么最大值的 position 應該在[lo, mid-1]
的范圍內。 然而,當我實現我的想法時,程序是無窮無盡的。 解決方案是使用[lo, mid]
作為下一次迭代。
我的問題是:為什么我不應該在第 9 行中使用mid-1
而不是mid
?
第一次編輯:有人問我為什么不只是排序並選擇第一個元素? 因為問題是在雙調數組中找到一個鍵(元素先上升然后下降)。 我的解決方案是找到數組的最大值,將其分成兩部分,分別使用 BinarySearch 查找鍵。 如果我對數組進行排序,我將破壞原始順序。
第二次編輯:詳細添加更多代碼和預期的 output。
public static int getMaxIndex(int[] a) {
int hi = a.length - 1;
int lo = 0;
while (lo < hi && a[lo] <= a[lo+1]) {
int mid = lo + (hi - lo) / 2;
if (a[mid] > a[mid-1]) {
lo = mid;
} else {
hi = mid - 1; // Should be mid, not mid-1, why?
}
}
return lo;
}
public static void main(String[] args) {
int[] a = {1, 2, 3, 5, 7, 9, 8, 6, 4}; // Bitonic array
System.out.println(getMaxIndex(a)); // Should be 5
}
數字嚴格遞增,索引后數字嚴格遞減
例如: [15, 20, 26, 5, 1]
如果數組僅包含唯一元素,則可以使用以下條件找到最大值
left index < right index
時迭代middle index
(如果沒有單個中間索引,則向左) arr[mid] < arr[mid + 1]
永遠不會拋出越界異常,因為left < right
不變量在循環中保持不變。 因此mid
(index) 將始終小於right
(index),因此在mid
之后至少有一個索引
int left = 0, right = arr.length - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (arr[mid] < arr[mid + 1]) {
left = mid + 1;
} else {
right = mid;
}
}
return arr[left]; // or arr[right]
15 20 26 5 1
l=0, r=4 l m r
m=2
a[m] > a[m+1] l r
so, r=m
l=0, r=2 l m r
m=1
a[m] < a[r+1] l,r
m=l+1
Now exit while loop l == r and return value at l or r
lo
卡在相同的索引上並導致無限循環。lo + 1 == hi
和arr[lo] < arr[hi]
的數據集都會將mid
設置為lo
( lo + (hi - lo) / 2
將是lo
),因此分配lo = mid
會導致無限環形你遇到的問題是你並不總是在改變mid
。 在您的示例中,有一點lo
是 4 並指向數組中的7
,而hi
是 5 並指向9
。 在lo
和hi
僅相差 1 的情況下, mid
設置為lo
。 在這里,您正在比較a[mid] > a[mid-1]
。 問題 1, mid-1
超出范圍,在極少數情況下會給出ArrayIndexOutOfBoundsException
。 其次,如果條件為true
,則將lo
設置為mid
,這是它已經擁有的值。 你無處可去。 您處於無限循環中。
我試過你的方法
System.out.println(getMaxIndex(new int[] { 3 , 8 })); // Expecting 1
我得到java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 2
解決方案在 Horse 的回答中。
在這里,雙調這個詞的bitonic
是,數組按升序排序,並且在某個點(可能是)之后它開始減少。
同樣,您必須找到陣列開始減少的 pivot 點(如果存在),如果您能夠找到該點, that's it
,這個關鍵點就是您的答案。
所以我附上了一些輸入/輸出序列以使其更清楚:
{1, 2, 3, 5, 7, 9, 8, 6, 4}; --> should return 5 (index at which element is maximum)
{15, 20, 26, 5, 1} --> should return 2 (index at which element is maximum)
{0, 1, 2, 3} --> should return 3 (index at which element is maximum)
現在你必須修改你的代碼,如下所示:
public static int getMaxIndex(int[] arr) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if(mid == 0 || mid == arr.length-1) {
// if no such pivotal point exist in sequence/array
return mid;
}else if(arr[mid] > arr[mid+1] && arr[mid] > arr[mid-1]){
// it's the pivotal point, where element at left side smaller and element at right side too
return mid;
}
if (arr[mid] < arr[mid + 1]) {
left = mid + 1;
} else {
right = mid;
}
}
return -1;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.