29. 两数相除
题目描述
给定两个(整数),被除数 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
。
方法1
思路
因为要求不使用乘除,mod运算,我们可以思考使用加减或者位运算
缺点:时间复杂度为O(n),这里n为问题要求的结果:商n,当被除数很大、除数很小时,效率非常低(比如,dividend = INT_MAX,divisor=1
)这个算法会超时,所以我们要试着在这个算法的基础上,分析此算法的瓶颈所在,进行优化,把复杂度降下来,一般o(n)的复杂度,我们要首先看一看能不能往O(logn)方向进行优化.
代码实现
class Solution {
public:
int divide(int dividend, int divisor) {
//溢出的情况
if(divisor==0 || (dividend==INT_MIN && divisor==-1))
return INT_MAX;
if(dividend == 0)
return 0;
int sign = ((dividend<0) ^ (divisor<0)) ? -1 : 1;
//C库函数 long int labs(long int x)返回x的绝对值
long a = labs(dividend);
long b = labs(divisor);
int ret = 0;
while(a >= b)
{
a = a-b;
//商等于循环能进行的减法操作的计数值
ret = ret+sign;
}
return ret;
}
};
方法2
思路
直接求出商的二进制表示的各个位的值
a = (q_0*2^0+q_1*2^1+q_2*2^2+...+q_i*2^i)*b+r
a-q_i*2^i*b = (q_0*2^0+q_1*2^1+q_2*2^2+...+q_(i-1)*2^(i-1))*b+r
这里q_i
的值为0
或者1
,注意:我们必须从高位到低位逐位试探(例如把7表示为二进制表示一样,需要从最高位开始试探)
代码实现
*/
class Solution {
public:
int divide(int dividend, int divisor) {
if(divisor==0 || (dividend==INT_MIN && divisor==-1))
return INT_MAX;
if(dividend == 0)
return 0;
int sign = ((dividend<0) ^ (divisor<0)) ? -1 : 1;
//C库函数 long int labs(long int x)返回x的绝对值
long a = labs(dividend);
long b = labs(divisor);
long ret = 0;
for(int i=31; i>=0;i--)
{ //即a >= (2^i)*b
if(a >= b<<i)
{
ret = ret | (1<<i);
a-=b<<i;
}
}
return sign==1?ret:-ret;
}
};
方法3
思路
和上面的思路本质上一样,不过上面使用了位运算的方式,这里使用了加减法的方式,将商的二进制表示的分解值都求出来相加。
代码实现
*/
class Solution {
public:
int divide(int dividend, int divisor) {
if(divisor==0 || (dividend==INT_MIN && divisor==-1))
return INT_MAX;
if(dividend == 0)
return 0;
int sign = ((dividend<0) ^ (divisor<0)) ? -1 : 1;
long a = labs(dividend);
long b = labs(divisor);
long ret = 0;
while(a >= b)
{
long temp = b;
//temp和multiple变量的值和状态保持一致
long multiple = 1;
//这里的条件判断中使用了temp << 1的方式,是为了
//在跳出循环时temp的值为破坏条件的前一个状态
while(a >= (temp << 1))
{
temp <<= 1;
multiple <<= 1;
}
a -= temp;
ret += multiple;
}
return sign==1?ret:-ret;
}
};