-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
二分查找
二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。其时间复杂度是 O(logn),所以是一直非常高效的查找算法。
不过,并不是什么情况下都可以用二分查找,它的应用场景是有很大局限性的,如下:
- 二分查找只能用在数据是通过顺序表来存储的数据结构上(数组):如果你的数据是通过其他数据结构存储的,则无法应用二分查找。
- 二分查找针对的是有序数据:如果数据没有序,我们需要先排序。但是针对存在频繁的插入和删除操作数据集合,维护有序的成本是很高的。
- 数据量太小不适合二分查找:如果要处理的数据量很小,完全没有必要用二分查找,顺序遍历就足够了。只有数据量比较大的时候,二分查找的优势才会比较明显。不过,如果数据之间的比较操作非常耗时,不管数据量大小,都推荐使用二分查找。比如,数组中存储的都是长度超过 300 的字符串,如此长的两个字符串之间比对大小,就会非常耗时。我们需要尽可能地减少比较次数,而比较次数的减少会大大提高性能,这个时候二分查找就比顺序遍历更有优势。
- 数据量太大也不适合二分查找:二分查找的底层需要依赖数组这种数据结构,而数组为了支持随机访问的特性,要求内存空间连续,对内存的要求比较苛刻。比如,我们有 1GB 大小的数据,如果希望用数组来存储,那就需要 1GB 的连续内存空间。
以下是二分查找的变形算法。
简单二分查找
适用于没有重复元素的有序数组。
public int binarySearch(int[] arr, int target) {
if (arr == null || arr.length == 0) {
return -1;
}
int low = 0;
int high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) {
return mid;
}
if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
变体一:查找第一个等于目标元素的位置
适用于存在重复元素的有序数组,并且是找到第一个值等于目标元素的情况。
public int binarySearch(int[] arr, int target) {
if (arr == null || arr.length == 0) {
return -1;
}
int low = 0;
int high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] > target) {
high = mid - 1;
} else if (arr[mid] < target) {
low = mid + 1;
} else { // arr[mid] == target
// 判断目标元素是否是第一个出现的
if (mid == 0 || arr[mid - 1] != target) {
return mid;
}
high = mid - 1;
}
}
return -1;
}
变体二:查找最后一个等于目标元素的位置
适用于存在重复元素的有序数组,并且是找到最后一个值等于目标元素的情况。
public int binarySearch(int[] arr, int target) {
if (arr == null || arr.length == 0) {
return -1;
}
int low = 0;
int high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] > target) {
high = mid - 1;
} else if (arr[mid] < target) {
low = mid + 1;
} else { // arr[mid] == target
// 判断目标元素是否是第一个出现的
if ((mid == arr.length - 1) || arr[mid + 1] != target) {
return mid;
}
low = mid + 1;
}
}
return -1;
}
变体三:查找第一个大于等于目标元素的位置
public int binarySearch(int[] arr, int target) {
if (arr == null || arr.length == 0) {
return -1;
}
int low = 0;
int high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] >= target) {
if (mid == 0 || arr[mid - 1] < target) {
return mid;
}
high = mid - 1;
} else if (arr[mid] < target) {
low = mid + 1;
}
}
return -1;
}
变体四:查找最后一个小于等于目标元素的位置
public int binarySearch(int[] arr, int target) {
if (arr == null || arr.length == 0) {
return -1;
}
int low = 0;
int high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] > target) {
high = mid - 1;
} else if (arr[mid] <= target) {
if ((mid == arr.length -1) || arr[mid + 1] > target) {
return mid;
}
low = mid + 1;
}
}
return -1;
}
Metadata
Metadata
Assignees
Labels
No labels