1. 程式人生 > 實用技巧 >二分法學習筆記第一版

二分法學習筆記第一版

二分法學習筆記第一版

1. 理論知識

  • 二分法可以變成一棵高度優化的二叉搜尋樹,適用條件

    資料有序

    支援隨機訪問

2. 應用場景

  • 二分搜尋常常用於優化暴力搜尋,快速求解,時間複雜度是O(logn)

3.二分演算法常見的三種類型

  • 搜尋特定值
/**
     * 子有序表中搜索target對應的下標,若不存在,則返回-1;
     * @param arr 升序陣列
     * @param target
     * @return
     */

public static int SerachSpeValue(int[] arr, int target){
    int low = 0, high = arr.length - 1, mid;
    while(low <= high){
        mid = low + (high - low) / 2; // 防止溢位
        if (arr[mid] == target)return mid;
        else if (arr[mid] < target)low = mid + 1;
        else high = mid - 1;
    }
    return -1;
}

watch out! 左邊下標是length - 1 ,即指向最後一個元素。所一while迴圈必須是low <= high ,不能是low < high。當low == high 時,這個時候不能退出迴圈,必須還要查詢一次。

  • 搜尋陣列中大於等於某個特定值的數
/**
     * 搜尋第一個大於等於target的值
     * @param arr 升序陣列
     * @param target
     * @return
     */
    public static int SearchFirstGreaterOrEqualTarget(int[] arr, int target){
        int low = 0, length = arr.length, high = length, mid; // 注意high是length ,不是length - 1
        while(low < high){ // <= 可能會造成死迴圈
            mid = low + (high - low) / 2;
            if (arr[mid] < target)low = mid + 1;   // 大於等於的數一定在mid後面
            else high = mid;                  // mid對應的數字有可能是第一個大於等於target的,也有可能是不是,需要縮小。
        }
        if (high == length)return -1; // 不存在的話,high = length
        return high;   // high對應第一個大於等於的數字
    }

**這裡high變成了length, 指向陣列最後元素的下一個位置,所以呢,while迴圈不可以取等號。極易產生死迴圈,通過模擬可以知道,最後返回值的下標為high,但是要考慮到如果這樣的值不存在咋辦,不存在時high為陣列長度,所以最後判斷以下即可
***
  • 搜尋陣列中小於某個特定值的數

這題的程式碼其實就是搜尋陣列中大於等於某個特定值的數的變形。最後返回結果的下標變成high-1就可以了。

/**
     * 搜尋第一個小於的數字,就是搜尋第一個大於等於target的值的變體,修改下搜尋不到的條件
     * if (arr[0] >= target)return -1;
     * 退出後返回high - 1;
     */

    public static int SearchLastLessTarget(int[] arr, int target){
        int low = 0, length = arr.length, high = length, mid;
        while(low < high){ // <= 會造成死迴圈
            mid = low + (high - low) / 2;
            if (arr[mid] < target)low = mid + 1;   // 大於等於的數一定在mid後面
            else high = mid;                  // mid對應的數字有可能是第一個大於等於target的,也有可能是不是,需要縮小。
        }
        if (high == 0)return high - 1; // 不存在的話,high = 0 ,則返回-1
        return high - 1;   // high對應第一個大於等於的數字,沒有返回length,減一後必然小於target。
    }

**這裡注意一下,如果最發現不存在這樣的數字,high指向0,所以減一後就返回-1了,也可以把return前面的if判斷給刪了。

  • 搜尋陣列中大於某個特定值的數
/**
     * 搜尋第一個大於target的值的下標,不存在則返回-1
     * @param arr 升序陣列
     * @param target
     * @return
     */
    public static int SearchFirstGreaterTarget(int[] arr, int target){
        int low = 0, length = arr.length, high = length, mid;
        while(low < high){ // <= 會造成死迴圈
            mid = low + (high - low) / 2;
            if (arr[mid] <= target)low = mid + 1;   // 大於target的數一定在mid後面
            else high = mid;                  // mid對應的數字有可能是第一個大於target的,也有可能是不是,需要縮小。
        }
        if (high == length)return -1;
        return high;
    }
  • 搜尋陣列中小於等於某個特定值的數
/**
     * 搜尋第一個小於等於target的數字,就是搜尋第一個大於target的值的變體,修改下搜尋不到的條件
     * if (arr[0] > target)return -1;
     * 退出後返回high - 1;
     */
    public static int SearchLastLessOrEqualTarget(int[] arr, int target){
        int low = 0, length = arr.length, high = length, mid;
        while(low < high){ // <= 會造成死迴圈
            mid = low + (high - low) / 2;
            if (arr[mid] <= target)low = mid + 1;   // 大於target的數一定在mid後面
            else high = mid;                  // mid對應的數字有可能是第一個大於target的,也有可能是不是,需要縮小。
        }
        // if (high == 0)return high - 1; 和下一句合併
        return high - 1;
    }