二分查找(折半查找)总结

二分查找分为通过数组的角标进行查找和通过元素数值进行查找


通过数组的角标进行查找:
通常用于数组数值有序的情况
正常实现:

public int binarySearch(int[] nums, int key) {
    int l = 0, h = nums.length - 1;
    while (l <= h) {
        int m = l + (h - l) / 2;
        if (nums[m] == key) {
            return m;
        } else if (nums[m] > key) {
            h = m - 1;
        } else {
            l = m + 1;
        }
    }
    return -1;
}

时间复杂度: O(logN)。

m 计算:
有两种计算中值 m 的方式:
m = (l + h) / 2
m = l + (h - l) / 2
为避免 l + h 加法溢出,最好使用第二种方式。

返回值:循环退出时如果仍然没有查找到 key,那么表示查找失败。可以有两种返回值:

-1:以一个错误码表示没有查找到 key
l:将 key 插入到 nums 中的正确位置

变种: 二分查找可以有很多变种,变种实现要注意边界值的判断。例如在一个有重复元素的数组中查找 key 的最左位置的实现如下:

public int binarySearch(int[] nums, int key) {
    int l = 0, h = nums.length - 1;
    while (l < h) {
        int m = l + (h - l) / 2;
        if (nums[m] >= key) {
            h = m;
        } else {
            l = m + 1;
        }
    }
    return l;
}

该实现和正常实现`有以下不同:

循环条件为 l < h
h 的赋值表达式为 h = m
最后返回 l 而不是 -1

时,不表示没有查找到 key,因此最后返回的结果不应该为 -1。为了验证有没有查找到,需要在调用端判断一下返回位置上的值和 key 是否相等。
参考资料


通过元素数值进行查找
LeetCode应用题目:
378 二维有序矩阵的 Kth Element
287 寻找重复元素(元素数值属于[1,n],,数组为乱序,要求时间复杂度<=O(N))

解题思路:通常需要找到最大最小值,确定mid后,根据mid值找到比mid大或者小的个数来重新界定边界,通常用于数组无序,但数组数值范围已知的情况

287 寻找重复元素

public int findDuplicate(int[] nums) {
        int l = 1,r = nums.length-1;
        while(l<=r){
            int mid = l+(r-l)/2;
            int cnt = 0;
            for(int i = 0;i<nums.length;i++){
                if(nums[i]<=mid)
                    cnt++;
            }
            if(cnt>mid)
                r = mid-1;
            else
                l = mid+1;
        }
        return l;
    }

378 有序矩阵的 Kth Element

public int kthSmallest(int[][] matrix, int k) {
        int m = matrix.length,n = matrix[0].length;
        int l = matrix[0][0],r = matrix[m-1][n-1];
        while(l<=r){
            int mid = l+(r-l)/2;
            int cnt = 0;
            for(int i = 0;i<m;i++){
                for(int j = 0;j<n;j++){
                    if(matrix[i][j]<=mid)
                        cnt++;
                }
            }
            if(cnt<k)
               l = mid+1;
            else
                r = mid-1;
        }
        return l;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值