二分查找小结

数据结构课程就有学习到二分法的思想和实现,但自己的动手实践太少,用二分法解题的练习也很少,但直到前段时间真正动手用二分法解题的时候才发现二分法里面的细节很多,边界条件很难把握,用 < 还是<=return left 还是 return right分不清。

二分查找的一些细节:

  1. 不要出现 else,而是把所有情况用 else if 写清楚,这样可以清楚地展现所有细节。

  2. 计算 mid 时需要防止溢出,代码中 使用left + (right - left) / 2来代替 (left + right) / 2 ,有效防止了 left 和 right 太大直接相加导致溢出。

  3. 若初始化 right 的赋值是 nums.length - 1,即最后一个元素的索引,则每次的查找区间相当于 [ left , right ] 即两端都闭区间;若初始化 right 的赋值是 nums.length,则查找区间相当于 [ left , right ) 即左闭右开区间。

    因此在while循环的条件处两种情况有所差别,第一种情况应当为**while(left <= right),即当left=right+1时终止,此时查找区间为 [right , right+1] 为空; 第二种情况应当为while(left < right)**,即当left==right时终止,此时查找区间为 [ right , right ) 为空。

根据以上几点,就大概可以解决二分查找的相关问题了,特别是第三点的总结让我受益匪浅。以下为总结的二分查找的两种

格式:

    int binary_search_case1(int[] nums, int target) {
        int left = 0, right = nums.length - 1; 
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1; 
            } else if(nums[mid] == target) {
                // 直接返回
                return mid;
            }
        }
        // 直接返回
        return -1;
    }
    int binary_search_case2(int[] nums, int target) {
         int left = 0, right = nums.length; 
            while(left < right) {
                int mid = left + (right - left) / 2;
                if (nums[mid] < target) {
                    left = mid + 1;
                } else if (nums[mid] > target) {
                    right = mid; 
                } else if(nums[mid] == target) {
                    // 直接返回
                    return mid;
                }
            }
            // 直接返回
            return -1;
    }

类似的,查找有序数组某元素第一次出现的位置的代码格式如下

    int left_bound(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else if (nums[mid] == target) {
                // 别返回,收缩左侧边界
                right = mid - 1;
            }
        }
        // 最后要检查 left 越界的情况
        if (left >= nums.length || nums[left] != target)
            return -1;
        return left;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值