二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求数组必须是升序。
时间复杂度为O(log n)。
Java中Arrays.binarySearch()
以下是Java版的二分查找,同时Java中Arrays工具类也提供了二分查找方法Arrays.binarySearch(int a, int key);
参数:
a - 要搜索的数组
key - 要搜索的值
返回:
如果它包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。插入点 被定义为将键插入数组的那一点:即第一个大于此键的元素索引,如果数组中的所有元素都小于指定的键,则为 a.length。注意,这保证了当且仅当此键被找到时,返回的值将 >= 0。
使用二分搜索法来搜索指定的 int 型数组,以获得指定的值。必须在进行此调用之前对数组进行排序(通过 sort(int[]) 方法)。如果没有对数组进行排序,则结果是不确定的。如果数组包含多个带有指定值的元素,则无法保证找到的是哪一个。
二分查找源码:
public static int binarySearch(int[] a, int key) {
return binarySearch0(a, 0, a.length, key);
}
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.
}
数据结构二分查找实现
/***
*
* @param a - 待查找的升序数组
* @param target - 待查找的目标值
* @return 返回 target的索引,找不到则返回-1
*/
public int search(int[] a , int target){
int i = 0;
int j = a.length-1;
while (i <= j){
int m = (i+j) >>> 1;
if (target < a[m]){
j = m-1;
}else if (a[m] < target){
i = m+1;
}else {
return m;
}
}
return -1
}
二分查找-改良版,返回最左边索引
若数组[0,3,5,5,5,7,10,12],元素有重复时,返回大于等于target最左边索引。适用场景:求排名,搜索插入位置
/***
*
* @param a - 待查找的升序数组
* @param target - 待查找的目标值
* @return 返回 >= target的最靠左索引
*/
public int binarySearchLeft(int[] a , int target){
int i = 0, j = a.length;
while ( i <= j){
int m = (i + j) >>> 1;
if ( target <= a[m]){
j = m-1;
}else {
i = m+1;
}
}
return i;
}
二分查找-改良版,返回最右边索引
若数组[0,3,5,5,5,7,10,12],元素有重复时,返回小于等于target最右边索引。适用场景:求前任,求后任。
/***
*
* @param a - 待查找的升序数组
* @param target - 待查找的目标值
* @return 返回 <= target的最靠右索引
*/
public int binarySearchRight(int[] a , int target){
int i = 0, j = a.length;
while ( i <= j){
int m = (i + j) >>> 1;
if ( target < a[m]){
j = m-1;
}else {
i = m+1;
}
}
return i-1;
}
LeetCode-704题-二分查找
题解
class Solution {
public int search(int[] nums, int target) {
int i = 0, j = nums.length - 1;
while(i <= j){
int m = (i+j) >>> 1;
if(target < nums[m]){
j = m - 1;
}else if(nums[m] < target){
i = m + 1;
}else{
return m;
}
}
return -1;
}
}
LeetCode-35题-搜索插入位置
题解:
class Solution {
public int searchInsert(int[] nums, int target) {
int i = 0, j = nums.length - 1;
while(i <= j){
int m = (i+j) >>> 1;
if(target <= nums[m]){
j = m - 1;
}else{
i = m + 1;
}
}
return i;
}
}