二分查找及其应用

二分查找是一种非常经典的查找算法,其应用场景也非常多,算法思路清晰,但是其效率很高。

/**
  * 二分查找
  * 如果数组中存在目标值,返回其对应下标
  * 如果数组中不存在目标值,则返回-1
  * */
public static int binarySearch(int[] arr,int target){
    int low = 0;
    int high = arr.length-1;
    while (low<=high){
        int mid = low+(high-low)/2;
        if(target<arr[mid]){
            high = mid-1;
        }
        else if(target>arr[mid]){
            low = mid+1;
        }
        else{
            return mid;
        }
    }
    return -1;
}

注意点:时间复杂度为O(logN),计算mid有两种方式,1) mid=(low+high)/2,2) mid=low+(high-low)/2,low+high有可能出现加法溢出,最好用第二种方式。3) 循环条件有两种方式,low<high和low<=high,如果是low<high,那么相应的high的赋值表达式就是high=mid,如果是low<=high,相应的high的赋值表达式就是high=mid-1。

应用一:求开方

    求一个数num的算术平方根sqrt,一个数num的算术平方根sqrt一定在0~num/2之间,并且满足sqrt=num/sqrt,可以利用二分查找在0~num/2之间查找sqrt。

public static int mysqrt(int x){
if (x<=1){
return x;
}
int low=1;
int high=x/2;
while (low<=high){
int mid=low+(high-low)/2;
int sqrt=x/mid;
if (sqrt<mid){
high=mid-1;
}
else if(sqrt>mid){
low=mid+1;
}
else{
return mid;
}
}
return high;
}

应用二:摆硬币

    给定n个硬币,在第i行摆i个硬币,求总共可以摆满多少行,可以利用二分查找。

public static int arrangeCoins(int n) {
    int low = 0;
    int high = n;
    while(low <= high){
        int mid = low + (high - low) / 2;
        long x = mid * (mid + 1L) / 2;
        if(x == n){
            return mid;
        }
        else if(x < n){
            low = mid + 1;
        }
        else high = mid - 1;
    }
    return high;
}

应用三:有序数组的 single element

    在一个有序数组中只有一个元素出现一次,其余元素均出现2次,找出这个元素,可以利用二分查找。

public static int singleNoDuplicate(int[] arr){
    int low=0;
    int high=arr.length-1;
    while (low<high){
        int mid = low+(high-low)/2;
        if (mid%2==1){
            mid--;
        }
        if(arr[mid]==arr[mid+1]){
            low=mid+2;
        }
        else{
            high=mid;
        }
    }
    return arr[low];
}

猜你喜欢

转载自www.cnblogs.com/earthhouge/p/8849773.html