二分法问题及其边界条件的探讨

本文探讨了二分法在处理边界条件时的重要性,解释了如何避免数值溢出并防止结果错误。通过分析LeetCode的69题和35题,总结了不同场景下的二分查找边界条件,区分了[left,right)和[left,right]两种情况,并提供了相应的代码实现。" 132154949,7144079,EEMD与改进鲸鱼算法优化的SVM电力负荷预测,"['支持向量机', '机器学习', '算法优化', '电力系统', '预测模型']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看二分法的一句代码,很有意思:

int mid = low + ((high - low) / 2);

这个与二分法求两数平均值的结果是一样的,为什么要这样写呢?

查阅资料后很好理解,这是为了避免数值溢出的问题。如果直接按照原来的思路来写:

int mid = (low + high) / 2;

C++本身对int类型的字符就有4Bytes(32位)的存储上限要求,也就是说int类型的字符的取值范围在-2^32~(2^32-1)。如果low和high本身就达到范围值了怎么办?就会造成报错溢出。

平时习惯用Python写,Python3避免了这个问题,只要不超出内存范围,就不需要Codinger设计担心这个问题。

有好的习惯,还可以写成:

int mid = (low+high)>>>1;

值得注意的是,这样写虽然可以避免溢出,但是会造成结果错误的情况:

int mid = high/2+ low/2;

当high或者low中两者都为奇数时,结果会错。

eg:high=3 low=5 则mid本应该等于4,但是这种算法算出来为1+2=3!!

对二分法的好处理(骚操作)有所理解后,看到了Leetcode 69 sqrt(x) 这道题目。本题目不能用内置函数来找到数的完全平方数的整数部分。起初是想建立一个HashMap,把x映射到x的平方上,然后再依次比较大小。但这个方法对十分大的数,尤其是Python的内存边界数无能为力。而且对于很大的数字必定会造成搜索空间巨大而超过时间限制。

一筹莫展之时,忽然发现其实这个就是查询问题的套路:给定某一个查询条件(这里就是平方不大于x),再给定一个搜索范围(0~x),再其中找到符合条件的数。稍微不同的是之前说的二分查找就是直接等于这个要找到的数,但是这里所说的整数部分解,其实就是最接近却又不大于x的数,其实就是个判断语句的条件不同而已,殊途同归。

故手撕代码如下:

left,right=0,x
while left<right:
    mid=left+(right-left+1)//2
    if mid*mid<=x:
        left=mid
    else:
        right=mid-1
return left

其中值得注意的边界条件有三点:

  1. left<right而不是left<=right
  2. left=mid而right=mid-1
  3. mid=left+(right-left+1)//2这里的1

结合Leetcode 35 Search Insert Position来看,如果列表中存在这个数就返回这个数的位置,如果不存在就返回大小顺序排列应该放的位置。发现也是一个给定了搜索条件和搜索范围的二分查找题目。

pointer1,pointer2=0,len(nums)-1
while pointer1<=pointer2:
    mid=pointer1+(pointer2-pointer1)//2
    if nums[mid]==target: return mid
    elif nums[mid]>target:
        pointer2=mid-1
    else:
        pointer1=mid+1
return pointer1

       这里的边界条件和Leetcode 69就完全不同了。仔细思考(抠脑壳)之后的tips:

  • 二分法的问题可以分类为[left,right)和[left,right]两种答案区间。
  • [left,right)可以直接代入[2,2),这种情况是错误的,所以跳出循环的条件就是left<right,必须是[2,3)才正确。而[left,right]的[2,2]是存在的,所以跳出循环的条件应该是left<=right。
  • 由上,同理,最后快结束循环的时候,假如[2,4]和[2,4),mid=3,如果执行left=mid+1,那就变成[4,4]和[4,4),可以看出再left<right的情况下,不能将mid+1来更新left指针。

未完待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值