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