1. 程式人生 > 其它 >java 高效方法實現二分法

java 高效方法實現二分法

技術標籤:演算法演算法二分法

題目要求:請實現有重複數字的有序陣列的二分查詢。
輸出在陣列中第一個大於等於查詢值的位置,如果陣列中不存在這樣的數,則輸出陣列長度加一。
先考慮這樣一個問題:對於一個有序陣列來說,什麼情況下是不存第一個大於等於 v的位置呢?
即:陣列中的所有數都比 v 小,可以寫成

if(a[n-1]<v)
    return n+1;

判完這個條件以後,aa 數組裡就一定可以存在一個位置是答案了。這樣的話,我們來設答案在閉區間[Left,right][Left,right]之間
當這個區間只剩下一個數,即LeftrightLeftright的時候,就是我們答案的位置了。

最開始,可能的區間為整個 aa 陣列[0,n-1][0,n−1]
下面我們用二分的方式對這個區間進行縮減
每次拿出中間的值 a[Mid]a[Mid] 和 vv 比較,那會有三種結果:大於、等於、小於
在這裡插入圖片描述
1、如果a[Mid] \gt va[Mid]>v
說明說明後面的那段都不可能是結果了。因為a[Mid]就是一個大於等於v的值了,後面的肯定都不可能是第一個。這樣的話,可能的答案區間就縮減成了[Left,Mid][Left,Mid]

Right = Mid;

2、如果a[Mid] = va[Mid]=v
這種情況和1相同
3、如果a[Mid] \lt va[Mid]<v
那說明,a[Mid]a[Mid]以及a[Mid]a[Mid]之前的都不可能是我們的結果,可能的答案區間縮減成了[Mid+1,Right][Mid+1,Right]。

Left = Mid+1;

因為現在陣列中肯定有一個位置是我們要求的結果,所以在縮減區間的過程中不會出現Left>RightLeft>Right的情況。所以,當LeftrightLeftright的時候我們就找到答案了,這個答案就是Left(Right),還要注意一點,本題要輸出的位置是從1開始的,但是我們的區間是用的陣列下標,所以最後要輸出Left+1(Right+1)。

public class Dichotomy {
    public static void main(String[] args) {
        int[] arr = {1, 2, 4, 4
, 5}; int i = upperBound(5, 4, arr); System.out.println(i); } /** * 二分查詢 * * @param n int整型 陣列長度 * @param v int整型 查詢值 * @param a int整型一維陣列 有序陣列 * @return int整型 */ public static int upperBound(int n, int v, int[] a) { if (a[n - 1] < v) { return n + 1; }//如果不存在這樣的數:即陣列中所有數字都比 int left = 0; int right = n - 1; while (left < right) { int mid = left + (right - left) / 2;//防溢位 if (a[mid] >= v) right = mid; else left = mid + 1; } return left + 1; } }