java 二分查找

java手撕二分查找在面试中常考,所以抽空在温习一波及几种二分查找常用变形写法(以作记录)。

二分查找也叫折半查找,每一次都与中间数据做比对大小,缩小查找区间的范围。

假设有10个数据,8,11,19,23,27,33,45,55,67,98,利用图分析

在这里插入图片描述
小结:
二分查找针对的是一个有序的数据集合也就是数组(这也成为了二分查找的一个重要局限性),查找思想有点类似分治思想。
每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0

二分查找时间复杂度:O(logn)

简单推导:假设有n个数据,每次查找后数据都会变为n/2,直到查找区间变为空。
也就是 n, n/2 , n/4 , n/8 , n/16 , ···,n/2^k , ···
在这里插入图片描述
可以看出来这是一个等比数列。 当 n/2^k = 1时,k就是总共缩小的次数,又因为每一次缩小操作只涉及到两个数据大小比较,所以,经过k次区间变小操作后时间复杂度为O(k). 求得 k = log2n
所以时间复杂度为O(logn)

这是惊人的查找速度,因为logn是一个非常“恐怖”的数量级,即便n非常非常大,对应的logn也很小。比如n等于2的32次方,这个数很大了吧?大约是42亿。也就是说,如果我们在42亿
个数据中用二分查找一个数据,最多需要比较32次

代码:二分查找

public class BinarySearch {


    public static void main(String[] args) {

        int[] a = {1, 3, 4, 6, 7, 8, 12, 13, 15, 16, 19, 21, 27, 27, 27, 31, 167, 989};

        int i = binarySerach(a, 27);
        System.out.println("二分查找下标为:" + i);//只要匹配到一个目标值就返回了

        int b = binarySerachInterval(a, 0, a.length - 1, 27);
        System.out.println("递归方式:" + b);

        int c = binarySerachFirstTarget(a, 27);
        System.out.println("查找第一个等于目标值下标:"+c);

        int d = binarySerachLastTarget(a, 27);
        System.out.println("查找最后一个等于目标值下标:"+d);

        int e = binarySerachFirstGreater(a, 5);
        System.out.println("查找第一个大于目标值的元素下标:"+e);

        int f = binarySerachFirstLess(a, 5);
        System.out.println("查找最后一个小于目标值的元素下标:"+f);


    }

    //二分查找底层依赖的是数组,除了数据本身之外,不需要额外的存储其他信息,是最省内存的存储方式
    public static int binarySerach(int[] a, int target) {

        int low = 0;
        int high = a.length - 1;

        int mid;

        while (low <= high) {

            mid = (low + high) >> 1;//这样写是有问题的,如果low或者high比较大的话,两者的和就会溢出,
            //改进的写法
            // mid = low + (high - low)/2;

            if (a[mid] == target) {
                return mid;
            } else if (a[mid] > target) {
                high = mid - 1;
            } else if (a[mid] < target) {
                low = mid + 1;
            }
        }

        return -1;
    }


    //递归的方式
    public static int binarySerachInterval(int[] a, int low, int high, int target) {
        if (low > high) return -1;

        int mid = low + ((high - low) >> 1);
        if (a[mid] == target) {
            return mid;
        } else if (a[mid] < target) {
            return binarySerachInterval(a, mid + 1, high, target);
        } else {
            return binarySerachInterval(a, low, mid - 1, target);
        }

    }


    //查找出现的一个目标值的位置
    public static int binarySerachFirstTarget(int[] a,int target){

        int low = 0;
        int high = a.length -1 ;

        int mid ;
        while (low <= high){
            mid = low + ((high - low)>>1);
            if (a[mid] < target){
                low = mid + 1;
            }else if (a[mid] > target){
                high = mid - 1;
            }else {
                //由于数组是有序的
                //a[mid-1] 当遍历到a[mid]==target值时候还要去看看 a[mid-1]是否也是==target
                //如果a[mid-1]不等于target则可以返回当前下标。
                if ((a[mid -1] != target) || (mid == 0)) {
                    return mid;
                }else {
                    high = mid -1;
                }
            }

        }

        return -1;
    }

    //查找出现的最后一个目标值的位置
    public static int binarySerachLastTarget(int[] a,int target){

        int low = 0;
        int high = a.length -1 ;

        int mid ;
        while (low <= high) {
            mid = low + ((high - low) >> 1);
            if (a[mid] < target){
                low = mid + 1;
            }else if (a[mid] > target){
                high = mid - 1;
            }else {

                if ((a[mid + 1] != target) || (mid == a.length-1)) {
                    return mid;
                }else {
                    low = mid +1;
                }

            }


        }

        return  -1;
    }


    //查找出现的大于一个目标值第一个的位置
    public static int binarySerachFirstGreater(int[] a,int target){

        int low = 0;
        int high = a.length -1 ;

        int mid ;
        while (low <= high) {
            mid = low + ((high - low) >> 1);

            if (a[mid] >= target){
                if ((mid == 0 ) || (a[mid-1] < target)) return mid;
                else  high = mid - 1;
            }else{
                low = mid + 1;
            }

        }

        return  -1;
    }

    public static int binarySerachFirstLess(int[] a,int target){


        int low = 0;
        int high = a.length -1 ;

        int mid ;
        while (low <= high) {
            mid = low + ((high - low) >> 1);

            if (a[mid] > target){
                high = mid - 1;
            }else{
                if ((mid == (a.length-1) ) || (a[mid+1] > target)) return mid;
                else low = mid + 1;
            }

        }
        return -1;
    }

}

希望面试遇到手撕二分查找能迅速写出来!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬瓜螺旋雪碧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值