簡體   English   中英

使用 BinarySearch 的變體來查找雙調數組中的最大值

[英]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]

如果數組僅包含唯一元素,則可以使用以下條件找到最大值

  1. left index < right index時迭代
  2. 計算middle index (如果沒有單個中間索引,則向左)
  3. 如果中間的值小於下一個元素,則向右移動
  4. 否則向左移動

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

OP的代碼分析

  1. 一個簡單的可重現示例是 [1, 2] - 這將導致lo卡在相同的索引上並導致無限循環。
  2. 任何減少到lo + 1 == hiarr[lo] < arr[hi]的數據集都會將mid設置為lolo + (hi - lo) / 2將是lo ),因此分配lo = mid會導致無限環形

你遇到的問題是你並不總是在改變mid 在您的示例中,有一點lo是 4 並指向數組中的7 ,而hi是 5 並指向9 lohi僅相差 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM