给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
示例 1:
输入: dividend = 10, divisor = 3
输出: 3
示例 2:
输入: dividend = 7, divisor = -3
输出: -2
说明:
被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。本题中,如果除法结果溢出,则返回 2^31 − 1。
方法一:最直接的算法当然是直接相减,模拟运算除法,然而当数据量大的时候,时间复杂度相当的大。。。
class Solution {
public:
int divide(long long dividend, long long divisor) {
if (dividend == INT_MIN && divisor == -1){
return INT_MAX;
}
if (divisor == 1){//如果除数是1,则无需相减,直接返回
return dividend;
}
if (divisor == -1){
return -dividend;
}
bool resultFlag = false;//结果是否为负数的flag
if (!((dividend >= 0 && divisor >= 0) || (dividend < 0 && divisor < 0))){
//如果非同号
resultFlag = true;
}
if (dividend < 0){
dividend = -dividend;
}
if (divisor < 0){
divisor = -divisor;
}
long long result = 0;//结果
while (dividend >= divisor){//一直相减
dividend -= divisor;
++result;
}
if (resultFlag){//如果标识结果为负数
result = -result;
}
return result;
}
};
上述方法感觉就是变相的暴搜。。。
方法二:下面将采用“以空间换时间”的策略,对上述算法进行优化。即使用一个数组,计算好一定数量的除数的n倍,这样可以减少相减的次数。
int divide(long long dividend, long long divisor) {
if (dividend == INT_MIN && divisor == -1){
return INT_MAX;
}
if (divisor == 1){//如果除数是1,则无需相减,直接返回
return dividend;
}
if (divisor == -1){
return -dividend;
}
bool resultFlag = false;//结果是否为负数的flag
if (!((dividend >= 0 && divisor >= 0) || (dividend < 0 && divisor < 0))){
//如果非同号
resultFlag = true;
}
if (dividend < 0){
dividend = -dividend;
}
if (divisor < 0){
divisor = -divisor;
}
//tempNValue[i]代表i倍的divisor(零除外)
long long tempNValue[100] = { INT_MAX, divisor};
int maxIndex = 1;//可以计算的最大的n倍divisor的值
while (maxIndex < 99){
tempNValue[++maxIndex] = tempNValue[maxIndex] + divisor;
}
long long result = 0;//结果
int beginIndex = maxIndex;
while (beginIndex >= 1){//一直相减
while (dividend >= tempNValue[beginIndex]){
dividend -= tempNValue[beginIndex];
result += beginIndex;
}
--beginIndex;
}
if (resultFlag){//如果标识结果为负数
result = -result;
}
return result;
}
虽然时间复杂度减少了很多,但是击败的用户很少,肯定与主流做法有很大的差距。。。
经翻阅前辈的算法,发现一种移位色解法。
这道题的基本思路使用移位和加减法替代乘除,因为任何INT除法运算可以表示为 X = y * N, N = 2^0 + 2^1 + 2^2 + 2^3 + ......。 这道题的难点在于 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。本题中,如果除法结果溢出,则返回 2^31 − 1。 这会造成两个麻烦:
移位有限制,无法使用long等类型
针对INT_MIN,无法直接转换为正数 对策:
提前判断是否移位越界
先提前dividend += abs(divisor),然后结果加1,然后在转为正数计算即可 附代码
class Solution {
public:
int divide(int dividend, int divisor) {
if(divisor == -1 && dividend == INT_MIN) return INT_MAX;
if(divisor == 1 && dividend == INT_MIN) return INT_MIN;
int sign = (dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0) ? -1 : 1;
if(divisor == INT_MIN) return dividend == INT_MIN ? 1 : 0;
divisor = abs(divisor);
int res = 0;
if(dividend == INT_MIN){
res += 1;
dividend += divisor;
}
dividend = abs(dividend);
if(divisor > dividend) return res*sign;
while(dividend != 1 && dividend != 0 && dividend > divisor){
int tmp = divisor; int cnt = 1;
while(dividend > (tmp << 1)){
if((tmp << 1) < tmp) break;
tmp = tmp << 1;
cnt = cnt << 1;
}
dividend -= tmp;
res += cnt;
}
res = (res + (dividend < divisor ? 0 : 1)) * sign;
return res;
}
};