二分法學習筆記第一版
阿新 • • 發佈:2020-08-29
二分法學習筆記第一版
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;
}