簡體   English   中英

算法:修改二進制搜索

[英]Algorithm: Modified Binary Search

我正試圖解決一個經典的面試問題,這個問題基本上是在列表上進行二元搜索,然后逐漸增加然后減少。 即使很明顯我們可以實現O(log n),但我無法弄清楚我寫的下面的代碼有什么問題:

#include <iostream>

using namespace std;


int binarySearch(int *A, int low, int high, int key)
{
    while(low < high)
    {
        int mid = (low + high) / 2;
        if(key < A[mid])
        {
            if(A[mid - 1] < A[mid] && A[mid] < A[mid + 1])
                high = mid - 1;
            else
                low = mid + 1;
        }
        else if(key > A[mid])
        {
            if(A[mid - 1] < A[mid] && A[mid] < A[mid + 1])
                low = mid + 1;
            else
                high = mid - 1;
        }
        else
            return mid;
    }

    return -(low + 1);
}


int main()
{
    const int SIZE = 8;
    int A[SIZE] = {3,5,7,14,9,8,2,1};
    cout<<binarySearch(A, 0, SIZE, 14);
    return 0;
}

我問這個問題的原因是因為我想知道兩件事。 1)代碼有什么問題 ,因為它失敗了某些值,如“14”。 2)可以改進嗎?

我認為你的代碼不能很好地處理數組的增加和減少部分。

而不是告訴你究竟如何做到這一點,這里有一些提示,我希望你能夠完成它:)

一種解決方案是首先找到數組從O(logn)中的遞增順序到遞減順序的點,然后基於此,在O(logn)中執行特殊版本的二進制搜索。

讓我知道,如果您不知道如何做到這一點,我會更多地解釋我的答案。

這是一個更完整的解決方案(僅供參考)

一種解決方案是首先找到數組從O(logn)中的遞增順序到遞減順序的點,然后基於此,在O(logn)中執行特殊版本的二進制搜索。

第一部分可以通過使用專門的二進制搜索找到array[i-1] <= array[i]的最后一個點來實現,其中mid索引移動條件是array[mid-1] <= array[mid]而不是是否為array[mid] <= target


示例代碼

為了防止我成為一名面試黑客,下面僅展示如何處理一個沒有任何重復的數組。 如有必要,代碼將很快刪除:

#include <stdio.h>
#include <stdlib.h>

int find_change_point(int array[], int low, int high, int array_size) {
  int mid;
  for (mid = (low + high) / 2; low <= high; mid = (low + high) / 2) {
    // if true, it implies the point is on the higher side
    if (array[mid - 1] <= array[mid]) {
      if (mid == array_size - 1) {
        return mid;
      }
      // since we already handles equality, only > is needed.
      if (array[mid] > array[mid + 1]) {
        return mid;
      }
      low = mid + 1;
    } else {
      // then simply imply the point is on the lower part
      high = mid - 1;
    }
  }
  return mid;
}

int main() {
  const int SIZE_1 = 8;
  int array_1[SIZE_1] = {3,5,7,14,9,8,2,1};
  int change_point = find_change_point(array_1, 0, SIZE_1 - 1, SIZE_1);
  printf("change_point_1 = %d\n", change_point);

  const int SIZE_2 = 9;
  int array_2[SIZE_2] = {3,5,7,14,15,16,17,19, 20};
  change_point = find_change_point(array_2, 0, SIZE_2 - 1, SIZE_2);
  printf("change_point_2 = %d\n", change_point);

  const int SIZE_3 = 9;
  int array_3[SIZE_3] = {9, 8, 7, 6, 5, 4, 3, 2, 1};
  change_point = find_change_point(array_3, 0, SIZE_3 - 1, SIZE_3);
  printf("change_point_3 = %d\n", change_point);
}

輸出是:

change_point_1 = 3
change_point_2 = 8
change_point_3 = 0

為了處理重復,您需要找到復制序列的左端和右端,並驗證它們是增加還是減少序列。

第二部分有很多種。 一個簡單的解決方案是將它們視為兩個數組,並對每個子數組執行一次二進制搜索以找到目標元素。

對於你的代碼我認為很多分支就像“if”操作。 以下是簡單的偽代碼供您參考:

while(1 < (high - low)){
     int mid = (low + high) >> 1;
     (key < A[mid]) ? high = mid : lo = mid;
}
return (key == A[lo]) ? lo : -1;

希望這可以幫到你。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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