二分查找(Binary Search)的幾種變種形式
阿新 • • 發佈:2018-10-22
位置 為什麽 常用 元素 整型 lock 二分查找算法 出現 特定
二分查找的幾種變種形式
二分查找是大家經常用而且也比較簡單的一種算法,查找的時間復雜度為O(logn)。wiki上的定義為:
是一種在有序陣列中尋找某一特定元素的搜尋演算法
搜尋過程從陣列的中間元素開始,如果中間元素正好是要尋找的元素,則搜尋過程結束;如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中尋找,而且跟開始一樣從中間元素開始比較。如果在某一步驟陣列為空,則代表找不到。這種搜尋演算法每一次比較都使搜尋範圍縮小一半。
簡單的二分查找算法相信大家都會寫,但是有時候經常會遇到一些變種形式,會讓人頭痛。
第一種:數組中沒有重復元素,找到該元素返回該元素的下標,否則返回該元素的插入位置。
非遞歸寫法:
public int binarySearch(int[] nums, int target) { int lo = 0; int hi = nums.length - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; if (target < nums[mid]) hi = mid - 1; else if (nums[mid] < target) lo = mid + 1; else return mid; } return low; }
遞歸寫法:
public int binarySearch(int[] nums, int target, int lo, int hi) { if (lo > hi) return lo; int mid = lo + (hi - lo) / 2; if (target < nums[mid]) return binarySearch(nums, target, lo, mid - 1); else if (nums[mid] < target) return binarySearch(nums, target, mid + 1, hi); else return mid; }
第二種:數組中可能含有重復元素,找出目標元素的第一次出現的位置,否則返回該元素的插入位置。
非遞歸寫法:
public int binarySearch(int[] nums, int target) {
int lo = 0;
int hi = nums.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (nums[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
return lo;
}
遞歸寫法
public int binarySearch(int[] nums, int target, int lo, int hi) {
if (lo > hi) return lo;
int mid = lo + (hi - lo) / 2;
if (nums[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
一點經驗,二分查找的過程其實很簡單,繁瑣的點就在於結束的邊界處,如果不熟練,一定不要怕麻煩,在紙上多畫畫檢驗下,看看最後結果是否正確。一個需要註意的點在於int mid = lo + (hi - lo) / 2;
為什麽不寫成int mid = (lo + hi) / 2
呢?因為lo + hi
可能會出現整型溢出。
其實上面的求邊界還有一種寫法:
public int binarySearch(int[] A, int target) {
int lo = 0
int hi = A.length;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;;
if (A[mid] < target) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
大家可以比較下兩種方法的不同點,其實不需要記這麽多寫法,容易把自己搞混,只需要記住一種正確寫法就好。
二分查找(Binary Search)的幾種變種形式