力扣704-二分查找

91 阅读2分钟

题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

思路:

假定有个数组 let nums = [1,2,3,4,5,8,9], 目标值 target = 4,需要从数组nums中找到target 4,并返回其下标3,若找不到 则返回 -1。
那么肯定是要对nums遍历的,退出遍历的条件是找到target,遍历有两个思路:1,暴力方式:按照0-nums.length依次遍历,找到target则返回下标并推出循环。2.既然是有序(升序数组),那么也就是数组的所有元素是从小到大排列,则此时二分(折半)查找显然效率更高。

二分查找主要思路:

首先,要明确查找范围,范围一定是[左下标,右下标],因为最后一个元素也是要比较的,所以 建议用闭区间,默认范围是[0,nums.length-1],即:left=0,right=nums.length-1 从中间位置开始比较,假设中间位置元素为nums[mid],则原数组被分为三部分

左边区域a: nums[0]~nums[mid-1],
中间元素b::nums[mid],
右边区域c::nums[mid+1]~nums[mid.length-1], 只需要比较nums[mid]和target 的大小,

  1. 若nums[mid]>target 则代表中间的数字比目标元素大,又因为有序,显然,查找的元素如果存在,则一定在左边区域,查找区间向左收缩,缩短到nums[0]~nums[mid-1].即 left不变,right=mid-1.
  2. 若nums[mid]<target 则代表中间的数字比目标元素小,又因为有序,显然,查找的元素如果存在,则一定在右边区域,查找区间向右收缩,缩短到nums[mid+1]~nums[mid.length-1].即right不变,left=mid+1. 3)若nums[index]==target,则代表目标值已经找到,直接返回index

依次循环,直到left >= right,代表已无查找区间,若还没有找到目标,代表循环完成,没有目标元素,则返回-1

关键元素

  1. 折半查找,则首先要找到中间位置的下标,最简单的方式是 (left + right)/2,但是,若数组很大,则有可能 left+right 数据过大溢出,则可以换成 left + (right-left)/2.
  2. 又因为下标一定是整数,而(right-left)/2 可能出现0.5这样的小数,为保证整数,则可以考虑用位运算符>>。

js代码

let searchNum = (nums,target)=>{
    let left=0,right=nums.length-1;
    while(left<right){
        let mid = left +( (right-left)>>1);
        if(nums[mid]>target){//中间元素比目标元素大,查找区间向左收缩
            right = mid-1;
        }else if(nums[mid]<target){//中间元素比目标元素小,查找区间向右收缩
            left = mid +1;
        }else{
            return mid;
        }
    }
    //循环结束,没有找到目标元素
    return -1;
}