二分查詢(一)——純粹的二分查詢

weixin_33850890發表於2018-09-24

LeetCode_35_SearchInsertPosition

題目分析:

找大於target的最小數的下標。

解法一:遞迴

public static int searchInsert(int[] nums, int target) {
    return binarySearch(0, nums.length, nums, target);
}

//左閉右閉[begin,mid] 遞迴
public static int binarySearch(int begin, int end, int[] list, int target){
    if(begin == end)
        return begin;

    int mid = begin + (end - begin) / 2;//防溢位

    if (target < list[mid])
        return binarySearch(begin, mid, list, target);
    else if(target > list[mid])
        return binarySearch(mid + 1, end, list, target);
    else
        return mid;//題目說明無重複 相等直接剪枝
}

解法二:迴圈

//左閉右閉[begin,mid] 迴圈
public static int searchInsert2(int[] nums, int target) {
    int begin = 0, end = nums.length;
    while(begin != end){
        int mid = begin + (end - begin) / 2;//防溢位
        if(target < nums[mid])
            end = mid;
        else if(target > nums[mid])
            begin = mid + 1;
        else
            return mid;//題目說明無重複 相等直接剪枝
    }
    return begin;
}

細節分析:

解法一二隻是形式不同,就以解法二為準,分析幾個細節。
1.mid = begin + (end - begin) / 2 有兩個注意點
  1)不能寫成 mid = (begin + end) / 2 否則begin + end可能溢位
  2)在迭代過程中,規模縮減到end - begin = 1的時候  mid計算出的結果是等於begin的。
2.begin = mid + 1 而不是begin = mid
    因為細節1中的第2點,可看出 如果begin = mid 可能會出現死迴圈。
3.end = mid 而不是 end = mid - 1
    同樣因為細節1中的第2點,end = mid就足以讓搜尋往左也不會出現死迴圈。
    mid - 1還會帶來的問題,試試這個輸入[1,3] target = 2
4.end = nums.length 而不是end = nums.length - 1
    因為taget大於所有值,需要返回陣列最後一個位置nums.length

一句話總結這個寫法:查詢[begin,end]閉區間範圍內的符合條件下標。

PS:之前看網上的無符號右移寫法mid = (begin + end) >>> 2;後來親測 2 >>> 2 == 0。與預期1不符。

相關文章