簡體   English   中英

如何在排序數組上使用二進制搜索來查找特定范圍內的整數數。 (有重復)

[英]How to use a binarysearch on a sorted array to find the number of integers within a certain range. (with duplicates)

假設你有一個排序的整數數組:

{3,4,4,6,10,15,15,19,23,23,24,30}

並且您希望找到4和23范圍內的整數數。

{4,4,6,10,15,15,19,23,23}

因此結果將是9。

我寫了一個二進制搜索實現,但我不確定如何修改它也考慮到可以有多個整數匹配范圍的上限的事實。

我想在方法簽名中添加一個布爾值來詢問是否要查找鍵的上限,但我不確定它是否可以在單個方法中完成,同時保持O(log(N))的復雜性。

或者是否有其他方法在O(log(N))時間內在排序數組中查找該范圍內的項目數?

這是我到目前為止:

int start = rangeBinarySearch(arr, 4, false);
int end = rangeBinarySearch(arr, 23, true); // true would indicate that I want the position of the last occurrence of the key.

int totalInRange = (Math.abs(end) - Math.abs(start) -1)


private static int rangeBinarySearch(int[] items, int key, boolean lastIndex) {
    if(items == null)
        throw new IllegalArgumentException();

    int start = 0;
    int end = items.length - 1;

    while(start <= end) {
        int mIndex = (start + end) / 2;
        int middle = items[mIndex];

        if(middle < key)
            start = (mIndex +1);
        else if(middle > key)
            end = (mIndex -1);
        else
            return mIndex; // Possible something here to find the upper bounds?
    }

    return -(start +1);
}

下限和上限的范圍二進制搜索是不同的 這里不同意味着它們具有不同的停止標准和返回步驟。

  1. 對於下限(左范圍) ,您可以調用以下函數來獲取值大於或等於它的排序數組中的索引,否則為-1。

     int binarySearchForLeftRange(int a[], int length, int left_range) { if (a[length-1] < left_range) return -1; int low = 0; int high = length-1; while (low<=high) { int mid = low+((high-low)/2); if(a[mid] >= left_range) high = mid-1; else //if(a[mid]<i) low = mid+1; } return high+1; } 
  2. 對於上限(右側范圍) ,您可以調用以下函數來獲取排序數組中的索引,其中值小於或等於它,否則為-1。

     int binarySearchForRightRange(int a[], int length, int right_range) { if (a[0] > right_range) return -1; int low = 0; int high = length-1; while (low<=high) { int mid = low+((high-low)/2); if(a[mid] > right_range) high = mid-1; else //if(a[mid]<i) low = mid+1; } return low-1; } 
  3. 最后 ,如果您想獲得此范圍內的元素數量,則可以根據上述兩個函數的返回值輕松實現。

     int index_left = binarySearchForLeftRange(a, length, left_range); int index_right = binarySearchForRightRange(a, length, right_range); if (index_left==-1 || index_right==-1 || index_left>index_right) count = 0; else count = index_right-index_left+1; 

測試 :(有重復)

    int a[] = {3,4,4,6,10,15,15,19,23,23,24,30};
    int length = sizeof(arr)/sizeof(arr[0]);

    int left_range = 4;
    int right_range = 23;
    int index_left = binarySearchForLeftRange(a, length, left_range); // will be 1
    int index_right = binarySearchForRightRange(a, length, right_range); // will be 9

    int count; // will be 9
    if (index_left==-1 || index_right==-1 || index_left>index_right)
        count = 0;
    else
        count = index_right-index_left+1;

編輯 :當然,您可以通過傳遞一個額外的標志來將前兩個函數合並為一個,以指示它是下限或上限,但如果不是,則會更清楚。 你的選擇!

如果您不學習算法,請使用標准函數:

    Arrays.binarySearch

你基本上需要首先出現你的第一個元素(4)和最后一個出現(23)和減去。 但是沒有必要(4)在那里,所以閱讀Arrays.binarySearch的文檔,它給你在哪里(4)。

如果你期望很多(4)s你必須編寫自己的binSearch,它返回第一個和最后一個索引:

找到第一次出現在索引i,如果有前一個看i / 2,如果有(4)看看i /​​ 4否則看3 * i / 4 ...

您需要執行兩次二進制搜索以查找rangeLow之前的最低索引和rangeHigh之后的highestIndex,這樣您就可以計算該范圍內的重復項。

當我們執行兩次二進制搜索時,這將給出o(2 log n)的時間復雜度。

private int searchArrayForNumbersInRange(int[] arr, int start, int end) {
    int leftIndex = searchLeft(arr, start);
    int rightIndex = searchRight(arr, end);
    int count;

    if (leftIndex < 0 || rightIndex < 0)
        return -1;
    if (rightIndex == leftIndex)
        count = 1;
    else {
        count = rightIndex - leftIndex;
    }
    return count;
}

private int searchLeft(int[] arr, int start) {
    int lo = 0;
    int hi = arr.length - 1;

    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;

        if (arr[mid] == start && arr[mid -1] < start) {
            return mid - 1;
        }

        if (arr[mid] >= start)
            hi = mid - 1;
        else
            lo = mid + 1;
    }

    return -1;
}

private int searchRight(int[] arr, int end) {
    int lo = 0;
    int hi = arr.length -1;

    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;

        if (arr[mid] == end && arr[mid+1] > end)
            return mid;

        if (mid <= end)
            lo = mid + 1;
        else
            hi = mid - 1;
    }

    return -1;
}

暫無
暫無

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

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