LeetCode/两数相除

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

思路跟快速幂差不多,通过不断累加减少使时间复杂度变成对数级,本质上是把其转换成二进制表示,这个二进制数就是商值
当然也可以使用多进制,但由于不能使用乘法,在32位限制的情况下,效率反而会变慢
当然这道题最难的地方还是处理各种溢出的细节

1. 递归缩小规模

递归从前往后
class Solution {
public:
    int divide(int dividend, int divisor) {
        if(dividend==INT_MIN&&divisor==-1) return INT_MAX;//处理溢出
        bool flag = false;
        if((dividend>0&&divisor>0)||(dividend<0&&divisor<0)) flag=true;//判断最终符号
        dividend = dividend>0?-dividend:dividend;
        divisor = divisor>0?-divisor:divisor;
        int count = dfs(dividend,divisor);//使分子分母均为负数,防止溢出
        return flag?-count:count;
    }
    int dfs(int dividend,int divisor){
        if(dividend>divisor) return 0;//边界条件
        int count = -1;
        int k = divisor; // 在后面的代码中不更新k
        if(k<INT_MIN-k) return -1;//防止溢出
        while((k+k)>=dividend){
            count = count + count; // 最小解翻倍
            k= k+k; // 当前测试的值也翻倍
            if(k<INT_MIN-k) break;//防止溢出
        }
        return count + dfs(dividend-k,divisor);//递归拆分求解
}
};

双重循环从前往后

class Solution {
public:
    int divide(int dividend, int divisor) {
    if(dividend==INT_MIN&&divisor==-1) return INT_MAX;//处理溢出
    bool flag = false;
    if((dividend>0&&divisor>0)||(dividend<0&&divisor<0)) flag=true;//判断最终符号
    dividend = dividend>0?-dividend:dividend;//使分子分母均为负数,防止溢出
    divisor = divisor>0?-divisor:divisor;
    int ans = 0;
    int MIN = INT_MIN>>1;
    while(dividend<=divisor){//从后往前计算
        int count = -1; int k = divisor;
        while(k>=MIN&& k>=dividend-k){//累加值要小于分子和上限,从前往后累加
            k+=k; count+=count;}//累加值找上限,计数找上限
        dividend-=k;//削减总量
        ans+=count;//总计数增加
    }
    return flag?-ans:ans;
}
};

2. 递归优化

递归从后往前
class Solution {
public:
    int target;
    int divide(int dividend, int divisor) {
        if(dividend==INT_MIN&&divisor==-1) return INT_MAX;//处理溢出
        bool flag = false;
        if((dividend>0&&divisor>0)||(dividend<0&&divisor<0)) flag=true;//判断最终符号
        dividend = dividend>0?-dividend:dividend;//使分子分母均为负数,防止溢出
        divisor = divisor>0?-divisor:divisor;
        if(dividend>divisor) return 0;//分子小于分母
        target = dividend;//记录待削减总量
        int sum = dfs(dividend,divisor,divisor,-1);
        return flag?-sum:sum;
    }
    int dfs(int dividend,int divisor,int k,int count){//要记录当前累加值,和当前计数值
        int sum = 0;
        if(k<INT_MIN-k){target-=k; return count;}//防止溢出,不用再翻倍了
        if((k+k)>=dividend)
            sum=dfs(dividend,divisor,k+k,count+count);//递归拆分求解
        if(k>=target){target-=k;return sum+count;}//从出递归真正开始运算,从后往前
        return sum;
}
};

同样可以使用容器将计算出来的累加值存储起来,实现从后往前遍历计算
跟递归从后往前实质上上等价的,本质上还是用空间换时间

posted @ 2022-06-02 21:02  失控D大白兔  阅读(23)  评论(0编辑  收藏  举报