开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
题目描述
给定两个整数,被除数 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 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。本题中,如果除法结果溢出,则返回 2^31 − 1。
解题思路
- 最直接的想法是直接除法运算,可是题目要求不能直接用除法
- 换一种思路,除法的商就是可以执行多少次减法。我们可以不断减除数并计数,但是考虑一下极端情况intmax/1时,运算复杂度为10^9,会超时,那怎么办呢?
- 如果做过快速幂这种倍增思想的题目,我们可以用类似的想法。一次减一个太慢了,我们可以一次减2个、4个、8个...这相当于每一次运算出一个二进制位,logn次即可完成。在解题中我们是由大到小枚举的,也就是先从比被除数小的最大2的指数次倍数开始。
- 但是要注意越界情况,比如-2^31/-1
- 除此之外,还应该注意符号问题,这里先把除数,被除数都转化为负数,最后结果再带上符号即可。
func divide2(dividend int, divisor int) int {
if dividend == int(^int32(^uint32(0)>>1)) && divisor == -1 {
return int(int32(^uint32(0) >> 1))
}
ans := 0
f := 1
if dividend > 0 {
dividend = -dividend
f = -f
}
if divisor > 0 {
divisor = -divisor
f = -f
}
k := 1
for dividend/2 <= divisor {
divisor += divisor
k += k
}
for k > 0 {
if dividend <= divisor {
ans += k
dividend -= divisor
}
k /= 2
divisor /= 2
}
return ans * f
}