目錄
歡迎瀏覽作者的GitHub
二分查找概述
條件:只能對已經排序好的列表進行查找。
需求:對搜索時間要求爲O(logn)一般都是二分查找。
概述:通過對經典二分查找的修改,達到日常查找的各種需求,
如1、查找某個值 target,2、查找第一個大於 target 的值,3、查找第一個小於 target 的值,4、查找第一個大於等於 target的值,5、查找第一個 小於等於 target 的值。
對於經典的算法,只要進行簡單的修改,即可滿足多種情況。
條件:left <= right
結束時:left 指向第一個不滿足 if 條件中的值,
如if(array[mid] < target):就是第一個大於等於target的值
如if(array[mid] <= target):就是第一個大於target的值
1、查找某個值 target
注意:如果不存在這個值,結束時:left > right,且 left 的座標爲第一個大於 target 的值。
public int binarySearchOne() {
int[] array = {0,1,2,3,4,5,6};
int target = 3;
int left = 0, right = array.length-1;
while(left <= right) {
int mid = (left+right)/2;
if(array[mid] == target)
return mid;
if(array[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return -1;
}
2、查找第一個大於(大於等於) target 的值
注意:結束時:left > right,如果 target 即爲最大值,則會產生數組越界,需要對 left 進行判斷,不能直接返回。
修改:大於等於也很好修改,只需要將 if 裏的判斷條件改爲 if(array[mid] < target) 即可。
public int binarySearchOne() {
int[] array = {0,1,2,3,4,5,6};
int target = 3;
int left = 0, right = array.length-1;
while(left <= right) {
//只修改了判斷的條件,相當於將小於等於歸爲一類。
if(array[mid] <= target)
left = mid + 1;
else
right = mid - 1;
}
return left;
}
3、查找第一個小於(小於等於) target 的值
注意:結束時:left > right,如果 target 即爲最小值,則會產生數組越界,需要對 right 進行判斷,不能直接返回。
修改:小於等於也很好修改,只需要將 if 裏的判斷條件改爲 if(array[mid] > target) 即可。
public int binarySearchOne() {
int[] array = {0,1,2,3,4,5,6};
int target = 3;
int left = 0, right = array.length-1;
while(left <= right) {
//只修改了判斷的條件,相當於將大於等於歸爲一類。
if(array[mid] >= target)
right = mid - 1;
else
left = mid + 1;
}
return right;
}
4、另一種寫法,幫助你理解二分查找
算法:查找第一個大於 target 值的座標。
注意:1、修改了循環條件:left < right,所以結束是 left == right。2、當遇到大於 target 值時,right = mid,保留當前可能的座標。
好處:不會產生數組越界的下標,如果 target 即爲最大值,則 left == right == array.length-1。否則一定會指向第一個大於 target 的座標。
public int binarySearchTwo(int[] array, int left, int right,int target){
while(left < right){ //修改了循環判斷
int mid = (left+right)/2;
if(array[mid] <= target) //大於要保留
left = mid + 1;
else
right = mid;
}
if(array[left] >= target) //最後結束時有left==right,如果一定存在,則不需要以下語句,直接返回即可。
return left;
return -1; //如果target即是最大值,則返回-1;
5、一個優秀的用二分查找尋找邊界的方法
例題:查找左右邊界,計算目標值的數量,使用了兩次查找第一個最大值。
public int search(int[] nums, int target) {
return binarySearch(nums, target + 0.5) - binarySearch(nums, target - 0.5);
}
private int binarySearch(int[] nums, double target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (right + left) /2;
if (nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return left;
}