二分法-数据类型定义导致的内存超限

力扣心得1 整数溢出导致的内存超限 —Q-69.x 的平方根

1、问题描述:一直显示【内存超限】


博主在学习二分法,做力扣69. x 的平方根这一题的时候,遇到一个内存超限的问题,抓耳挠腮了好久,都没有找到原因在哪:
在这里插入图片描述

题目要求不使用 pow(x, 0.5) 或者 x ** 0.5等自带功能,求出一个非负整数的算术平方根。使用二分法的思想本身倒是很简单,通过左右两个指针不断去接近其算术平方根即可
在检查了几遍自己大体思路没问题后,我开始针对这个测试案例进行思考,最终发现了问题~

先上干货,debug后的正确代码:

class Solution {
    public int mySqrt(int x) {
        int left=0;
        int right=x;
        int res=-1;
        while(left<=right){
            int mid=(left+right)/2;
            if((long)mid*mid>x){//在判断条件中,中间指针mid前加上(long),避免mid^2超出int类型上限
                right=mid-1;
            }else if(mid*mid<=x){
                res=mid;
                left=mid+1;
            }
        }
        return res;
    }
}

2、原因与解决办法

我对测试案例进行观察,发现2147395599这个数字好像比较特别,好像是int类型数组的上限也是2147开头的数字,于是去查询了一下:
在这里插入图片描述
这里我就发现似乎找到了问题所在了 ,于是写了个脚本测试了一下,到底mid是在哪个地方出问题了:

public static void main(String[] args) {
        int a1 = 46341;
        int square1 = a1 * a1;
        int a2 = 46340;
        int square2 = a2 * a2;
        System.out.println(square1);
        System.out.println(square2);
}

输出:

-2147479015//square1  实际46341^2=2147488281
2147395600//square2

这里由于square被定义为int类型,因此出现了整数溢出,应该输出输出为2147488281的结果,最后变成了:-2147479015。而本题报错的测试用例2147395599处于2147395600~2147488281

超限过程

下面我们快来看一下这个内存超限的过程:
我们可以看一下第一次进入这个while循环的时候,mid就变成了107369780,这时候整型溢出就已经开始了,实际上107369780^2>>x,然而却因为整型溢出,被赋值成负数,从而错误的执行
else if(mid*mid<=x)这条语句,将left指针变成107369781。
在这里插入图片描述
但是如果仅仅是一直进入这个循环,只是left一直往右移动,顶多只是计算结果错误,还不至于内存超限
坏就坏在mid往右移动的时候,有的计算结果在内存超限后,不光会错误地把mid*mid的结果变成-2147479015这样的负数,还会因为溢出变成一些错误的正数,因此,还可能会进入if(mid*mid>x)这个循环,所以,leftright指针会像在上图中这样反复横跳,从而导致内存超限。

博主用编译器打印了一下,样最后leftright会在哪两个值上一直反复横跳,这是最后输出的结果:

mid			-715915930
left		-715915929
mid			715739835
left		715739836
mid			-715915930
left		-715915929
mid			715739835
left		715739836
mid			-715915930
left		-715915929

结果显示,mid最终在-715915930715739835之间反复横跳,导致内存超限

最后,在判断前加个long定义一下数据类型就可以了~

这是个小问题,希望大家有则改之,无则加勉,永远都不会受到bug困扰,我们下期再见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值