题目
整数除法链接
给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 ‘*’、除号 ‘/’ 以及求余符号 ‘%’ 。
注意:
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [$-2^{31} $,
2
31
−
1
2^{31} − 1
231−1]。本题中,如果除法结果溢出,则返回
2
31
−
1
2^{31} − 1
231−1
题解
解题思路
-
不用除号/实现除法,第一时间想到用减法完成,同时计算减了多少个被除数,即为商。但减法需特别注意a,b异号的情况,正数/负数=负数,直接用减法会导致结果为整数且越来越大,因此需要对被除数和除数进行取反处理,使俩数处于同号。那么问题来了,两个数是都取正数还是都取负数呢?
-
由于负数的取值边界绝对值比正数取值边界大1,若都取正数,则会越界,eg: a = $-2^{31} $, b = -1,取正数a会越界。
注意点
- 该题容易出现溢出的情况,被除数、除数及商的最终范围必须在 [$-2^{31} $, 2 31 − 1 2^{31} − 1 231−1]内,需要特别考虑a,b两者异号边界情况,需对a,b进行取绝对值/取负数操作.
解法1
public int divide(int a, int b) {
if(b == 0) return -1;
if (a == Integer.MIN_VALUE && b ==-1) return Integer.MAX_VALUE;
boolean flag = false;
if ((a < 0 && b>0) ||(a >0 && b<0)) flag = true;
if(a > 0) a = -a;
if(b > 0) b = -b;
int count = 0;
while(a <= b) {
a = a-b;
count++;
}
return flag? -count :count;
}
- 时间复杂度:O(N)
- 空间复杂度:O(1)
解法2
public int divide(int a, int b) {
int flag = 0;
if (a ==Integer.MIN_VALUE && b == -1) return Integer.MAX_VALUE;
// 简化代码,使用int记录a,b为正数的个数, flag =2或0 即同号,结果不需要取反
if (a > 0) {
a = -a;
flag++;
}
if (b > 0) {
b = -b;
flag++;
}
int count = 0;
while (a <= b) {
int k = 1;
int tmp =b ;
while (tmp >= Integer.MIN_VALUE >>1 && a <= tmp <<1) {
tmp = tmp << 1;
// k++; k++计算乘了多少个2,计算减了b的数量需要计算2^k.
k = k + k; // 计算2的幂指数
// 这里需考虑极限情况, a = -2^31, b =-1情况下, 减了2^31次,但会溢出,因此k=-2^31,故下面count取负数即可
}
a -= b;
count -= k;
}
return flag == 1 ? count : -count;
}
- 时间复杂度:O(logN*logN)
- 空间复杂度:O(1)
总结
该题目本质用了减法替代除法并使用二分查找优化时间复杂度