二分查找学习总结

二分查找

不必纠结每次中间的数字两边的数字数量不一样,

真正影响的是中间那个数字到底该不该加入下一次的查找中

左闭右闭 [left, right]

int search(int* nums, int numsSize, int target) {
    int left = 0;
    int right = numsSize - 1;
    while (left <= right) {
        int middle = left + (right - left) / 2;
        if (target < nums[middle]) {
            right = middle - 1;
        } else if (target > nums[middle]) {
            left = middle + 1;
        } else {
            return middle;
        }
    }
    return -1;
}

左闭右开 [left, right)

int search(int* nums, int numsSize, int target) {
    int left = 0;
    int right = numsSize;
    while (left < right) {
        int middle = left + (right - left) / 2;
        if (target < nums[middle]) {
            right = middle;
        } else if (target > nums[middle]) {
            left = middle + 1;
        } else {
            return middle;
        }
    }
    return -1;
}

模版

int searchInsert(int nums[], int numsSize, int target) {
    int left = 0;
    int right = numsSize - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;

        if (nums[mid] == target) {
            // 处理相等的情况,例如返回 mid 或执行相关逻辑
            return mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }

    // 处理其他情况,这里可以返回 left 或 right + 1,具体取决于需求
    return left;
}

【二分查找】详细图解_二分查找法流程图-CSDN博客

要点

返回值

实际上要看判断条件和while()条件来判断返回值的内容,一般以 left 为主,如果 ==mid的条件放在上面,基本就是两个返回值,一个是当找到了mid 就返回了 另一个就是没有找到 返回false等

35. 搜索插入位置 - 力扣(LeetCode)

int searchInsert(int* nums, int numsSize, int target) {
    int left = 0;
    int right = numsSize - 1;
    int mid = 0;
    while(left <= right){
        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 left;
}

思考为何目标值不存在于数组中,返回left

nums = [1,3,5,6], target = 0
nums = [1,3,5,6], target = 2

当目标值不存在于数组中,最后一次循环进入条件left==right

两种情况:nums[mid] < target目标值在当前后一个,应当插入位置为当前mid+1

此时进行操作left = mid + 1,并且此时right = mid

nums[mid] > target目标值在当前前一个,应当插入位置为当前mid

此时进行操作right = mid - 1,并且此时left = mid

由此可以得到我们可以返回left或者right+1

在力扣提交都是可以通过的。

278. 第一个错误的版本 - 力扣(LeetCode)

同理看看这道题,最后应当return什么?

循环结束的最后一次left = right

输入:n = 5, bad = 4
对对对错错

此时经过不断地缩小范围,进入循环后mid指向第4个版本(所求答案)

此时left = right = mid一定是错误正确版本的交接的两个的一个

若此时为错误版本进行right = mid - 1操作,此时 left = mid,而所求答案是mid

若此时为正确版本进行left = mid + 1 操作,此时right = mid,而所求答案是mid + 1

由此可以得到我们可以返回left或者right+1

思考此时 mid 一定是错误正确版本的交接的两个的一个 还是 唯一后面的错误版本或者前面的正确版本

  1. 循环条件:
    • 循环条件是 left <= right,即当 leftright 相等时仍然继续循环。
    • 这确保了循环结束时 leftright 指向的是同一个位置。
  2. 更新操作:
    • isBadVersion(mid) 为真时(错误版本),更新 right = mid - 1,使得 right 指向错误版本之前的位置。
    • isBadVersion(mid) 为假时(正确版本),更新 left = mid + 1,使得 left 指向正确版本之后的位置。
int firstBadVersion(int n) {
    int left = 0;
    int right = n;
    int mid = 0;
    while(left <= right) {
        mid = left + (right - left)/2;
        if(isBadVersion(mid)) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return left;
}

红蓝染色法

35. 搜索插入位置 - 力扣(LeetCode)

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

核心要素

注意区间开闭,三种都可以
循环结束条件:当前区间内没有元素
下一次二分查找区间:不能再查找(区间不包含)mid,防止死循环
返回值:大于等于target的第一个下标(注意循环不变量)
循环不变式描述为L的左边恒小于x,R的右边恒大于等于x

四种类型

有序数组中二分查找的四种类型(下面的转换仅适用于数组中都是整数)

  1. 第一个大于等于x的下标: low_bound(x)
  2. 第一个大于x的下标:可以转换为第一个大于等于 x+1 的下标low_bound(x+1)
  3. 最后一个一个小于x的下标:可以转换为第一个大于等于 x 的下标左边位置, low_bound(x) - 1;
  4. 最后一个小于等于x的下标:可以转换为第一个大于等于 x+1 的下标左边位置, low_bound(x+1) - 1;


如有错误烦请指正。

感谢您的阅读

  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值