Given two integers dividend
and divisor
, divide two integers without using multiplication, division and mod operator.
Return the quotient after dividing dividend
by divisor
.
The integer division should truncate toward zero.
Example 1:
Input: dividend = 10, divisor = 3
Output: 3
Example 2:
Input: dividend = 7, divisor = -3
Output: -2
Note:
- Both dividend and divisor will be 32-bit signed integers.
- The divisor will never be 0.
- Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. For the purpose of this problem, assume that your function returns 2^31 − 1 when the division result overflows.
题意:
给两个整数,求两个数相除的余数,要求不使用乘法、除法、取余运算。
note:除数与被除数均为32位有符号整数;保证除数不为0;并且假设编译环境使用32位所能存储的数值范围为[-2^31, 2^31-1],如若结果发生溢出则返回2^31-1。
分析:
一种比较直接的思路可以使用辗转相减法,直到dividend<divisor.即可返回相减的次数。
如果除数很小,而被除数很大,辗转相减法必然效率极其低下,事实证明边界值均在测试样例中。见Code1.
所以另一种思路可以首先判断出被除数与除数之间的倍数关系,但是由于题目要求不可以使用乘除法,因此这里可以使用位移运算代替,然后再在小范围内求出精确结果。见Code2
以上两种得到的结果最后均需要判断是否发成了溢出。
Code1
class Solution {
public:
int divide(int dividend, int divisor) {
int flag=1;
long long a = dividend, b = divisor;
if(a<0){
a=-a;
flag*=-1;
}else if(a==0){
return 0;
}
if(b<0){
b=-b;
flag*=-1;
}else if(b==1){
return dividend;
}
if(a==b)
return flag;
if(b==1){
return a-1;
}
int sum=0; // 以上均为处理边界特殊情况
while(a>=b){
a-=b;
++sum;
}
return sum*flag;
}
};
结果:
Runtime: 2020 ms, faster than 27.56% of C++ online submissions for Divide Two Integers.
Memory Usage: 13.7 MB, less than 68.85% of C++ online submissions for Divide Two Integers.
Code2:
class Solution {
public:
int divide(int a, int b) {
long long signal = (a<0 ^ b<0)?-1:1; // 使用异或运算判断a,b是否异号
int shift = 0; // 用于记录位移量
long long dividend = a>0?a:-(long long)a;
long long divisor = b>0?b:-(long long)b;
while(dividend<<shift >= divisor)++shift;
int bits = shift-1; //bits 记录dividend大于divisor的最大倍数,这里用位移表示。
long long ans=0;
while(bits>=0){
if(dividend >= divisor<<bits){ // 依次减小位移量,精确最终的结果
dividend -= divisor<<bits;
ans += 1LL<<bits;
}
--bits;
}
ans *= signal;
if(ans<numeric_limits<int>::min() || ans>numeric_limits<int>::max()){ //判断溢出
return numeric_limits<int>::max();
}
return ans;
}
};
结果:
Runtime: 12 ms, faster than 99.63% of C++ online submissions for Divide Two Integers.
Memory Usage: 13.8 MB, less than 29.59% of C++ online submissions for Divide Two Integers.
可见使用位移操作可以使程序的运行速度提升两个量级。
Code2 & Python
class Solution:
def divide(self, dividend: int, divisor: int) -> int:
sift , signal = 0 , 1
if dividend < 0:
signal *= -1
dividend = -dividend
if divisor < 0:
signal *= -1
divisor = -divisor
while dividend>>sift >= divisor:sift+=1
bits = sift-1
ans=0
while bits>=0:
if dividend >= divisor<<bits:
dividend -= divisor<<bits
ans += 1<<bits
bits-=1
INT_MIN, INT_MAX = -(1<<31), (1<<31)-1
ans *= signal
if ans<INT_MIN or ans>INT_MAX:
return INT_MAX
return ans
结果:
Runtime: 56 ms, faster than 58.53% of Python3 online submissions for Divide Two Integers.
Memory Usage: 13.3 MB, less than 5.26% of Python3 online submissions for Divide Two Integers.