LintCode | Easy | 二分查找 | Binary Search

题目

给定一个排序的整数数组(升序)和一个要查找的整数target,
用O(logn)的时间查找到target第一次出现的下标(从0开始),
如果target不存在于数组中,返回-1。

样例

在数组 [1, 2, 3, 3, 4, 5, 10] 中二分查找3,返回2。

挑战

如果数组中的整数个数超过了2^32,你的算法是否会出错?

解题思路

首先看题目,实现二分查找,有一个需求是查找到target第一次出现的下标。
如果按常规方法

public int binarySearch(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        while(left < right)
        {
            mid = (left + right) / 2;
            if(target > nums[mid])
                left = mid + 1;
            else if(target < nums[mid])
                right = mid - 1;
            else
                return mid;
        }
        return -1;
    }

那不一定能查找到target第一次出现的下标。
正确处理二分查找及其变体,我们需要想清楚两个问题:
* 循环结束条件
* 循环过程中的区间划分和区间选择

重点是循环的每一步都完全排除不可能区间,终止条件一定要让循环能够终止

分析本题,left 和 right 为数组左右边界的下标,mid为数组中间元素下标,array为数组,target为要查找的数字。

初始条件:
left = 0, right = array.length - 1.
保持:
mid = (left + right)/2.
target > array[mid] ,说明[left, mid]区间内没有target,新区间为[mid + 1, right]。
target < array[mid],说明[mid, right]区间内没有target,新区间为[left, mid - 1]。
target = array[mid],因为数组允许重复,[left, right]区间内都有可能有target,
但是我们需要的是数组中第一个出现的target,故可以排除[mid + 1, right],新区间为[left, mid]。
结束:
如果target不存在于array中,最后结果必然是left > right,所以我们可以将终止条件设置为left > right。
如果target存在于array中,最后的结果是left == right ,终止条件为left == right。
所以终止条件为left >= right,循环条件即为left < right。

按此条件,在循环结束时必然是 left == right ,而此时并不能确定target在不在array中。
需要加一步判断,即在循环结束时,判断array[left] == target。
若等于则找到,返回left,若不等于则说明未找到,返回-1。

最后为了防止left + right的溢出,令mid = (right - left)/ 2 + left。

代码实现


   /**
     * 
     * @param nums: The integer array.
     * @param target: Target to find.
     * @return: The first position of target. Position starts from 0.
     */
    public int binarySearch(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int mid;
        while(left < right)
        {
            mid = (right - left) / 2 + left;
            if(target > nums[mid])
                left = mid + 1;
            else if(target < nums[mid])
                right = mid - 1;
            else
                right = mid;
        }
        if(nums[right] == target)
            return right;
        return -1;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值