算法描述
1.前提:有已排序的数组
2.定义左边界L,右边界H,确定搜索范围,循环执行二分查找
3.获取中间索引M=Floor((L+R)/2)
4.获取中间索引A[M] 与待搜索的值T进行比较
- A[M] == T 表示找到,返回中间索引
- A[M] > T,中间值右侧的元素都大于T,无须比较,M-1设置为右边界,继续查找
- A[M] < T,中间值左侧的元素都小于T,无须比较,M-1设置为左边界,继续查找
LeetCode第704题
算法实现
public class BinarySearch {
public static void main(String[] args) {
int[] array = {1, 5, 8, 11, 19, 22, 31, 35, 40, 45, 48, 49, 50};
int target = 40;
int idx = binarySearch(array, target);
System.out.println(idx);
int i = recursiveBserach(array, 0, array.length - 1, target);
System.out.println(i);
}
//循环版二分查找
public static int binarySearch(int[] nums, int target) {
int low = 0, high = nums.length - 1, mid;
while (low <= high) {
mid = (low + high) >>> 1;
// mid = (low + high) /2;
int midVal = nums[mid];
if (midVal == target) {
return mid;
} else if (midVal < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
/**
* 递归算法实现二分查找
*
* @param nums 数组
* @param low 左下标
* @param high 右下标
* @param value 要查找的值
* @return
*/
private static int recursiveBserach(int[] nums, int low, int high, int value) {
if (low > high) return -1;
// 找出中间下标
int mid = (high +low) >>> 1;
if (nums[mid] == value) {
return mid;
} else if (nums[mid] > value) {
return recursiveBserach(nums, low, mid - 1, value);
} else {
return recursiveBserach(nums, mid + 1, high, value);
}
}
}
解决整数溢出问题
问题描述
int l = 0;
int h = Integer.MAX_VALUE - 1;
int m = (l + h) / 2;
//第一次没问题
System.out.println(m);
//在右侧
l = m+1;
m = (l + h) / 2;
System.out.println(m);
当 l 和 r 都较大时,l + r 有可能超过整数范围,造成运算错误,解决方法有两种:
int m = l + (r - l) / 2;
还有一种是:
int m = (l + r) >>> 1;
JDK 实现
Arrays.binarySearch
// Like public version, but without range checks.
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
int key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
二分查找常见变形
查找第一个等于给定值的元素
public static int binarySearchLeft(int[] nums, int target) {
int low = 0, high = nums.length - 1, mid;
while (low <= high) {
mid = (low + high) >>> 1;
int midVal = nums[mid];
if (midVal == target) {
if (mid == 0 || nums[mid - 1] != target) {
return mid;
} else {
high = mid - 1;
}
} else if (midVal < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
查找最后一个等于给定值的元素
public static int binarySearchRight(int[] nums, int target) {
int low = 0, high = nums.length - 1, mid;
while (low <= high) {
mid = (low + high) >>> 1;
int midVal = nums[mid];
if (midVal == target) {
if (mid == nums.length - 1 || nums[mid + 1] != target) {
return mid;
} else {
low = mid + 1;
}
} else if (midVal < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
第一个大于等于目标值的下标(数组中可能不存在目标值)
public static int bsearchFirstOver(int[] nums, int target) {
int low = 0, high = nums.length - 1, mid;
while (low <= high) {
mid = (low + high) >>> 1;
int midVal = nums[mid];
if (midVal >= target) {
if (mid == 0 || nums[mid - 1] < target) {
return mid;
} else {
high = mid - 1;
}
} else {
low = mid + 1;
}
}
return -1;
}
最后一个小于等于目标值的下标(数组中可能不存在目标值)
public static int bsearchLastAccess(int[] nums, int target) {
int low = 0, high = nums.length - 1, mid;
while (low <= high) {
mid = (low + high) >>> 1;
int midVal = nums[mid];
if (midVal <= target) {
if (mid == nums.length - 1 || nums[mid + 1] > target) {
return mid;
} else {
low = mid + 1;
}
} else {
high = mid - 1;
}
}
return -1;
}