一、概述
二分查找算法 ,是一种在
有序数组
中查找某一特定元素的搜索算法。 搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。
二、常见算法
1. 有序数组中查找target
public int binarySearch(int[] arr, int target) {
if (arr == null || arr.length == 0) {
return -1; //没有找到
}
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] == target) {
return mid; //找到目标值所在位置
} else if (arr[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1; //没有找到
}
2. 有序数组中查找 >=target 的最左位置
二分法其实可以把数组进行无限二分,最终当数组无法进行二分时,便是退出条件。
public int binarySearch(int[] arr, int target) {
if (arr == null || arr.length == 0) {
return -1;
}
int left = 0;
int right = arr.length - 1;
int ans = -1; //新增一个标记,用于记录>=target的最左元素位置。
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] >= target) {
ans = mid; //先记录下这个位置,如果mid位置的前一个值<target,则直接返回当前这个mid值。
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
3. 有序数组中查找 <=target 的最右位置
解题方法与在有序数组中查找 >=target 的最左位置类似。
public int binarySearch(int[] arr, int target) {
if (arr == null || arr.length == 0) {
return -1;
}
int left = 0;
int right = arr.length - 1;
int ans = -1; //新增一个标记,用于记录<=target的最右元素位置。
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] <= target) {
ans = mid; //先记录下这个位置,如果mid位置的前一个值<target,则直接返回当前这个mid值。
left = mid + 1;
} else {
right = mid - 1;
}
}
return ans;
}
4. 局部最小值问题
无数数组arr,一定保证任意位置i和i+1不相等。
- 左边界:若 arr[0]<arr[1],0位置算是局部最小值。
- 右边界:若 arr[N-1]<arr[N-2],N-1位置算是局部最小值。
- 中间部分:若存在 arr[i-1]>arr[i] 且 arr[i]<arr[i+1],则i位置是局部最小值。
请你找到并返回1个 arr 中的最小值。
public int findMin(int[] arr) {
if (arr == null || arr.length == 0) {
return -1;
}
int len = arr.length;
if (len == 1) {//只有一个元素
return 0;
}
if (len == 2) {//两个元素
return arr[0] < arr[1] ? 0 : 1;
}
// 大于两个元素,使用二分法查找。
int left = 0;
int right = len - 1;
// 要预留3个数(left,mid,right)才进入循环。
while (left <= right - 1) {
int mid = (left + right) / 2;
if (arr[mid] < arr[mid-1] && arr[mid] <= arr[mid+1]) {
return mid;
}
if (arr[mid] > arr[mid-1]) {
right = mid - 1;
}
if (arr[mid] > arr[mid+1]) {
left = mid + 1;
}
}
// 最终剩2个数的时候,再对比一下。
return arr[left] < arr[right] ? left : right;
}