ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【剑指Offer】1.整数除法

2021-11-23 21:02:14  阅读:215  来源: 互联网

标签:15 Offer int 整数 减去 相除 除法 被除数 除数


创建时间: November 22, 2021 2:54 PM
最后编辑时间: November 22, 2021 4:21 PM
标签: 位运算, 数学
网址: https://leetcode-cn.com/problems/xoh6Oh/
难度: 简单

题目

输入2个int型整数,它们进行除法计算并返回商,要求不得使用乘号*、除号/及求余符号%。当发生溢出时,返回最大的整数值。假设除数不为0。例如,输入15和2,输出15/2的结果,即7。

分析

这个题目限制我们不能使用乘号和除号进行运算。一个直观的解法是基于减法实现除法。例如,为了求得15/2的商,可以不断地从15里减去2,当减去7个2之后余数是1,此时不能再减去更多的2,因此15/2的商是7。我们可以用一个循环实现这个过程。

但这个直观的解法存在一个问题。当被除数很大但除数很小时,减法操作执行的次数会很多。例如,求\((2^{31}-1 )/1\),减1的操作将执行\(2^{31}-1\)次,需要很长的时间。如果被除数是\(n\),那么这种解法的时间复杂度为\(O(n)\)。

我们需要对这种解法进行优化。可以将上述解法稍做调整。当被除数大于除数时,继续比较判断被除数是否大于除数的2倍,如果是,则继续判断被除数是否大于除数的4倍、8倍等。如果被除数最多大于除数的2k倍,那么将被除数减去除数的2k倍,然后将剩余的被除数重复前面的步骤。由于每次将除数翻倍,因此优化后的时间复杂度是\(O(logn)\)。(:这里减去除数的2k倍,而不是k倍,是因为本题ban掉了乘号* ,因此要实现被除数减去除数的倍数,只能通过将除数通过自己加自己的方式进行翻倍,即value+=value ,所以倍数是2k倍,即2的整数倍。)

下面以15/2为例讨论计算的过程。15大于2,也大于2的2倍(即4),还大于2的4倍(即8),但小于2的8倍(即16)。于是先将15减去8,还剩余7。由于减去的是除数的4倍,减去这部分对应的商是4。接下来对剩余的7和除数2进行比较,7大于2,大于2的2倍(即4),但小于2的4倍(即8),于是将7减去4,还剩余3。这一次减去的是除数2的2倍,对应的商是2。然后对剩余的3和除数2进行比较,3大于2,但小于2的2倍(即4),于是将3减去2,还剩余1。这一次减去的是除数的1倍,对应的商是1。最后剩余的数字是1,比除数小,不能再减去除数了。于是15/2的商是4+2+1,即7。

一些细节

  • 结果溢出
    java中int的取值范围是\([-2^{31},2^{31}-1]\),因此只有一种情况下,结果才会溢出,即\(-2^{31}/(-1)=2^{31}\)
  • int的最小值
    可以用Integer.MIN_VALUE 表示,也可以用0x80000000 表示(最高位是符号位,1表示负数,其他位全为0,根据补码可以计算出值为\(-2^{31}\))
  • 正负号
    同号相除为正,异号相除为负。先同号相除,再定正负。
    思考:使用正数相除还是负数相除?
    答:负数相除,因为负数最小值的绝对值比正数大,因此负数转正数可能会溢出。使用负数相除时,采用的方法是基于加法实现除法 ,与前面的例子类似。

代码

class Solution {
    public int divide(int a, int b) {
        //唯一溢出的情况: -2^31 / -1 =2^31 ,溢出
        if(a==Integer.MIN_VALUE && b==-1)return Integer.MAX_VALUE;
        //被除数为0,结果也为0
        if(a==0)return 0;
        //同号相除为正,异号为负
        int negative=2;
        if(a>0){
            a=-a;
            negative--;
        }
        if(b>0){
            b=-b;
            negative--;
        }
        //这里将运算双方转为负数相除,因为负数的绝对值比正数的绝对值大1,所有运算范围比正数大
        int res=divideNegative(a,b);
        return negative==1?-res:res;

    }
    //定义两个负数的除法运算
    public int divideNegative(int a,int b){
        //存放结果
        int res=0;
        //基于加法实现负数的除法操作
        while(a<=b){
            //用value实现除数b的不断翻倍
            int value=b;
            //times是除数b的倍数
            int times=1;
            //value>=0xc0000000是为了防止value+value溢出,0xc0000000等于Integer.MIN_VALUE/2
            while(value>=0xc0000000 && a<=value+value){
                times+=times;
                value+=value;
            }
            res+=times;
            a-=value;
        }
        return res;

    }
}

标签:15,Offer,int,整数,减去,相除,除法,被除数,除数
来源: https://www.cnblogs.com/ajietext/p/15595269.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有