leetcode学习记录:二分查找法

leetcode 704 二分查找。链接:https://leetcode.cn/problems/binary-search

题目描述:

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

示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

你可以假设 nums 中的所有元素是不重复的。

n 将在 [1, 10000]之间。

nums 的每个元素都将在 [-9999, 9999]之间。

解题思路:

设定数组的起始位置是start为0,末尾位置是length-1。

主要逻辑:将target 和数组的中间数mid进行比较,如果nums[mid]<target, 就将start赋值为mid+1, 如果nums[mid]>target,就将end赋值为mid-1, 如果都不是那就是nums[mid]和target的值相等,返回mid的值就是所需要的数组下标,往后start和end的更新值将会进入下一轮循环,直到找到或者说找不到跳出循环。

边界处理:如果一开始target就比数组nums的最大值大或者比最小值小那么就没有必要进入循环进行比较了。

代码及分析与优化

之前写的代码:

function search(nums: number[], target: number): number {
    let start =0;//起始位置
    let end =nums.length-1;//终点位置
    if(target>nums[end]||target<nums[start]){//特殊情况判断
        return -1;
    }
    while(start<=end ){//主要逻辑
        let mid=start+ Math.floor((end-start)/2);//解法多样,需要注意别溢出
        if(nums[mid]<target){
            start=mid+1;
        }else if(nums[mid]>target){
            end=mid-1;
        }
        else if(nums[mid]===target){
            return mid;
        }
    }
        return -1;
};

这一版主要是最初按照自己的逻辑写的,稍微需要留意和判断的地方就是,为什么nums[mid]<target的时候将start赋值为mid +1 而不是mid, 其实是一方面因为num[mid]已经确定不是target了,我们为了尽量缩小范围直接将原本的mid值进行剔除,另一方面反向思考:如果说将start的值赋值为mid,那么可能会存在死循环的情况,比如如果进入某一个循环需要处理的就只剩数组中的两数的时候。(理解之后,可以直接简单这么记:跟target比较过的mid的值是不会进入下一次循环的)。

我出过错的地方:

mid的取值问题

我之前是这么写的:let mid=(end + start)/2;。这样写可能会存在数组越界的情况。end+start的值有可能超过javascript能表示的数字类型的最大值。如果超过的话,JavaScript 会按照 IEEE 754 标准进行舍入,导致结果不准确。

解决办法:

使用 start + Math.floor((end - start) / 2) 可以避免精度问题。

因为 start + Math.floor((end - start) / 2) 不会超过最大值, 因为 end - start 一定小于等于原来的数组长度,这样就不会导致精度问题了

代码虽然能够跑通,但是不够精简,下面是优化之后的代码:

function search(nums: number[], target: number): number {
    let start = 0;
    let end = nums.length - 1;
    while (start < end) {
        let mid = start + Math.floor((end - start) / 2);
        if (nums[mid] < target) {
            start = mid + 1;
        } else if (nums[mid] > target) {
            end = mid;
        } else {
            return mid;
        }
    }
    return nums[start] === target ? start : -1;
}

优化点:

  1. 使用start<end代替start<=end,这样可以保证每次循环都能够缩小查找范围,节省查找时间。

  1. 将边界处理融入一个nums[start] === target ? start : -1中。我们仔细思考在循环条件是start<end时我们的边界处理逻辑和循环跳出的时候。不会进入循环的情况就只有单个数字的数组,如果nums[start]也就是nums[0],刚好start就是所求的值,如果不是那么就是返回-1。如果进入循环没能找到符合条件的值,那么nums[start]和target也肯定不会相等,直接返回-1即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值