29. 两数相除
给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
提示:
- 被除数和除数均为 32 位有符号整数。
- 除数不为 0。
- 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [−231,231−1]。本题中,如果除法结果溢出,则返回 2 31 − 1 2^{31} − 1 231−1。
解题思路: 此题我没解出来,直接参考了网友Grandyang的解法,大致的思路是,利用位运算求解。下面从数学上我证明一下这个解法的合理性。
证明:
设被除数为a, 除数为b,商为c,余数为d,则a和b的关系可以表示为下面式子
a
=
b
∗
2
n
1
+
b
∗
2
n
2
+
.
.
.
+
b
∗
2
n
i
+
.
.
.
+
b
∗
2
n
n
+
d
a=b*2^{n_1}+b*2^{n_2}+...+b*2^{n_i}+...+b*2^{n_n}+d
a=b∗2n1+b∗2n2+...+b∗2ni+...+b∗2nn+d
那么商c的二进制表示即为
n
1
n
2
.
.
n
i
.
.
n
n
n_1n_2..n_i..n_n
n1n2..ni..nn.
此题的解法代码也即是按照上述证明步骤写的。
class Solution {
public:
int divide(int dividend, int divisor) {
if (dividend == INT_MIN && divisor == -1) return INT_MAX;
long m = labs(dividend), n = labs(divisor), res = 0;
int sign = ((dividend > 0) ^ (divisor > 0)) ? -1 : 1;
if (n == 1) return sign == 1 ? m : -m;
while (m >= n) {
long t = n, p = 1;
while (m >= (t << 1)) {
t <<= 1;
p <<= 1;
}
res += p;
m -= t;
}
return sign == 1 ? res : -res;
}
};