leetcode29.两数相除

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

返回被除数 dividend 除以除数 divisor 得到的商。

示例 1:

输入: dividend = 10, divisor = 3
输出: 3

示例 2:

输入: dividend = 7, divisor = -3
输出: -2

说明:

被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [$2^31$,  $2^311$]。本题中,如果除法结果溢出,则返回 $2^311$。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/divide-two-integers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

完整代码

基本思想

  • 这道题可以用减法的形式去实现,统计被除数中除数的个数,前提是这两个数都要转化成正数
  • 难点:越界的情况如何处理???

我要哭了,看来我要好好研究研究,开展个越界专题了
下面的代码测试的时候结果正确,提交后超时

class Solution {
public:
    int divide(int dividend, int divisor) {
        int res=0;
        bool flag=false;
        if(dividend==0||divisor==0)
            return 0;
        if(divisor==1)
            return dividend;
        if(dividend==INT_MIN&&divisor==INT_MIN){
            return 1;
        }
        else if(dividend==INT_MIN){//被除数是INT_MIN时
            if(divisor>0){
                flag=true; 
                dividend=INT_MAX-divisor+1;
                res=1;
            }
            else{
                divisor=-divisor;
                dividend=INT_MAX-divisor+1;
                res=1;
            }
                             
        }
        else if(divisor==INT_MIN){//除数是INT_MIN时
            return 0;
        }
        else{
        if(dividend>0&&divisor<0){
            flag=true;
            divisor=-divisor;
        }
        else if(dividend<0&&divisor>0){
            flag=true;
            dividend=-dividend;
        }
        else if(dividend<0&&divisor<0){           
             divisor=-divisor;
             dividend=-dividend;
        }
        }
        while(dividend>=divisor){
            ++res;
            dividend-=divisor;
            if(res==INT_MAX){//结果是正数时,直接返回res即可
                if(flag==false)
                    break;
                else{//结果是负数时,只有当二者相等时,结果是INT_MIN,似乎也没有等于INT_MIN的情况了
                    if(dividend==divisor)
                        return INT_MIN;
                    else
                        break;
                }
            }
               
        }
        return (flag==true)? -res:res;
    }
};

好了,参考了人家的思想,自己的疑问一点一点解决

  1. 越界如何处理?
    其实也就是除数为1,或者-1,会出现越界,单独讨论就可以。
    定义成比传入的参数更大的数据类型,例如:long

参考人家的第一种思想:递归

首先来说明下,对于两个正数而言,如何不用乘除取余运算来计算两个数相除:规定被除数用a表示,除数用b表示,商用res表示,且a,b都大于0。
利用递归的思想,借助减法来实现。

(之前是统计被除数a中有多少个除数b,借助循环每次都减去一个除数b,统计能减多少次。这种思路并不是不可以,但是,结果是多少就要循环多少次,对于结果是INT_MAX,要循环INT_MAX次,提交结果只通过了几个就超时了。)

其实,可以在上述思想上,进行优化,将除数进行倍增。初始时,如果a<b,结果就是0;下面考虑a>=b的情况,商res初始化为1,如果a>=b+b,那相应的res也将变成res=res+res,直到a<b时,被除数变成a-b,继续上述运算,直到a<b。

class Solution {
public:
    int divide(int dividend, int divisor) {
        long res=0;
        int flag=1;
        
        if(dividend==0||divisor==0)
            return 0;
        
        if((dividend>0&&divisor<0)||(dividend<0&&divisor>0))
            flag=-1;
        
        long a=dividend;
        long b=divisor;
        
        a=(a>0)?a:-a;
        b=(b>0)?b:-b;
        
        res=div(a,b);
       
        if(res>INT_MAX){
                if(flag==1)
                    return INT_MAX;
                else{
                    return INT_MIN;
                }
        }
        return (flag==-1)?-res:res;
    }
private:
    long div(long a,long b){
        if(a<b)
            return 0;
        long res=1,b1=b;
        while(b+b<=a){
            res+=res;
            b+=b;
        }
        return res+div(a-b,b1);
    }
};
执行结果:通过
显示详情
执行用时 :0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗 :8.2 MB, 在所有 C++ 提交中击败了79.14%的用户

移位思想
这题也太难了,代码我都背下来了,但是也很难说清解题思想

尝试着来解释下:
基本思想:
a x = b ax=b
目标:求x

参考:leetcode

class Solution {
public:
    int divide(int dividend, int divisor) {
        //用移位的方法来处理,没太看明白,先尝试着写一下
        
        if(dividend==0)//被除数为0,结果为0
            return 0;
        
        if(dividend==divisor)//被除数等于除数,结果为1
            return 1;
        
        //下面的判断是为了排除INT_MIN转化为正数越界的情况
        if(divisor==INT_MIN)//除数是INT_MIN,由于所有的数(只看绝对值,这里已经排除了等于的情况)都比INT_MIN的绝对值小,结果为0
            return 0;
        int add=0;
        if(dividend==INT_MIN){
            if(divisor==-1)
                return INT_MAX;
            if(divisor==1)
                return INT_MIN;
            dividend+=(divisor>0)?divisor:-divisor;//这种情况结果要特殊处理
            add=1;
        }
        
        //将负数转化为正数
        bool flag=false;
        if((dividend>0&&divisor<0)||(dividend<0&&divisor>0))
            flag=true;
        dividend=(dividend>0)?dividend:-dividend;
        divisor=(divisor>0)?divisor:-divisor;
        
        //下面开始求商
        //思想:求10/2的商,10=2x5(二进制:101)
        int res=0;
        for(int i=31;i>=0;--i){
            int temp=dividend>>i;
            res=(res<<1)+(temp>=divisor);
            if(temp>=divisor)
                dividend-=divisor<<i;
        }
       
       
        res+=add;        
        return (flag==true)? -res:res;
        
    }
};
执行结果:通过
显示详情
执行用时 :4 ms, 在所有 C++ 提交中击败了84.95%的用户
内存消耗 :8.2 MB, 在所有 C++ 提交中击败了80.77%的用户
发布了217 篇原创文章 · 获赞 9 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_31672701/article/details/103811047