携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情
题目描述
给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
示例 1:
输入: dividend = 10, divisor = 3 输出: 3 解释: 10/3 = truncate(3.33333..) = truncate(3) = 3 示例 2:
输入: dividend = 7, divisor = -3 输出: -2 解释: 7/-3 = truncate(-2.33333..) = -2
提示:
- 被除数和除数均为 32 位有符号整数。
- 除数不为 0。
- 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果除法结果溢出,则- - 返回 231 − 1。
题目元素
- 给定一个被除数一个除数,它们的范围都是32位有效整数,包括整数负数0。
- 在不使用乘法、除法、模运算等求出这两个数的商,商值的绝对值向下取整。
解题思路
- 求两个数的商,不使用乘除法及模运算,首先想到的就是对被除数进行加减操作。而对于整数和2的乘法可以替换成这个整数带符号左移一位,对于整数和2的除法可以替换成这个整数带符号右移一位。
- 被除数和除数可能为正数也可能为负数,所以要涉及到整数的正负判断,二进制的最高位是符号位,所以可以对整数带符号右移31位,剩下的一位就是符号位,来判断该数是正数还是负数。
- 正整数的绝对值要比负数的绝对值小1,所以可以将被除数和除数转成负数进行操作,避免溢出。
- 可以采用每次 减去除数的二倍。。。四倍。。。八倍。。。直到剩下的差小于当前这个数,再依次将这个临界数除以2。。。直到差小于最原始的除数。即得到解
代码实现
public static int divide(int dividend, int divisor) {
// 当被除数为0直接返回0
if (dividend == 0) {
return 0;
}
// 标志最终值是否需要取反,true需要取反
boolean revertFlag = false;
// 将两个数转成负数
if (((dividend >>> 31) & 1) == 0) {
// 正数
revertFlag = true;
dividend = -dividend;
}
if (((divisor >>> 31) & 1) == 0) {
revertFlag = !revertFlag;
divisor = - divisor;
}
// 除数为1或-1
if (divisor == -1) {
if (dividend == Integer.MIN_VALUE) {
return revertFlag ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}else {
return revertFlag ? dividend : -dividend;
}
}
// 依次减原始除数的二倍
// 当前被除数剩余未减的数
int last = dividend;
// 当前增加到的除数的倍数
int nowSubtract = divisor;
// 增大到nowSubtract时对除数的倍数
int end = 1;
// 已经对被除数扣减过的除数的倍数
int ans = 0;
// 注意这里必须要加上nowSubtract大于最小值的一半,不加上的话它的2倍就会溢出,变成一个正数,导致计算错误
while (last <= nowSubtract && nowSubtract > Integer.MIN_VALUE >> 1) {
last -= nowSubtract;
ans += end;
nowSubtract <<= 1;
// 记录当前已经扣减的次数
end <<= 1;
}
// 剩下的被除数已经小于当前的除数
while (last <= divisor) {
// 只有当增大过nowSubtract才能对它做缩小操作,否则就变成除数的几分之一了
if (end > 1) {
end >>= 1;
nowSubtract >>= 1;
}
// 一直缩小到小于剩余被除数
if (nowSubtract < last){
continue;
}
// 扣减
last -= nowSubtract;
// 扣减次数累加
ans += end;
}
// 注意如果要转成正数,需要注意是否溢出
if (!revertFlag && ans == Integer.MIN_VALUE) {
return Integer.MAX_VALUE;
}
return revertFlag ? -ans : ans;
}