代码随想录算法训练营第一天| 704. 二分查找

Leetcode Link:二分查找

代码随想录:超详解

题目原文

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

你必须编写一个具有 O(log n) 时间复杂度的算法。

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。
  2. n 将在 [1, 10000]之间。
  3. nums 的每个元素都将在 [-9999, 9999]之间

分析

  1. 给定的数据不重复有序排列
  2. 时间复杂度要求为对数级(一般来说“砍成几半”是最容易想到的关于对数级复杂度的方向)
  3. 返回值为某数组元素的下标或-1

结论:本题可以使用二分查找法,不能使用一般的暴力穷举法(O(n))

题解与要点

One possible Answer:左闭右开 [a, b)

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size();//要点①
        while(left < right){ // 要点②
            int middle = left + ((right - left) / 2); // 要点③
            if(nums[middle] > target){
                right = middle; // 要点④
            }
            else if(nums[middle] < target){
                left = middle + 1; // 要点⑥
            }
            else {
                return middle;
            }
        }

        return -1;
    }
};
要点

①左右边界:左侧边界为下标0的元素(区间包含此元素);右侧边界指向“越界”的nums[nums.size()]元素,意为开区间,实际上用不到。

注:此处右边界不可以写为right = nums,size() - 2,这个语句实际上指向区间内的nums[nums.size() - 2],会导致右侧边界错误缩小,最后一个元素被排除在搜索区间之外。

②循环条件:因为使用左闭右开区间抽象约束“循环中不变的那一块区域,一直被囊括在搜索区间的那块区域(循环不变量)”,当left == rightright并不在搜索区间内,所以不适用<=

middle中间值索引的计算left + ((right - left) / 2)等价于middle = (right + left)/2,采用前者的原因是防止索引值过大,超出数据类型所规定的最大值。

例如:假设 int 类型最大值是 1000,而 left = 600,right = 800

  • 方法1:(600 + 800) / 2 = 1400 / 2 = 700,但在计算 600+800 时就已经溢出了
  • 方法2:600 + ((800 - 600) / 2) = 600 + (200 / 2) = 600 + 100 = 700,不会溢出

④右边界迭代:中间值大于目标值,应当缩小右边界。尽管middle不是目标值target,但由于右边界为开区间,right = middle并未将middle包含在下一次的搜索区间内。

⑤左边界迭代:中间值小于目标值,应当缩小左边界。由于左边界为闭区间,需避免将不合要求的中间值middle囊括在区间内,因此middle+1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值