29. 两数相除
题目描述
给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。
整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8 ,-2.7335 将被截断至 -2 。
返回被除数 dividend 除以除数 divisor 得到的 商 。
注意:假设我们的环境只能存储 32 位 有符号整数,其数值范围是 [−231, 231 − 1] 。本题中,如果商 严格大于 231 − 1 ,则返回 231 − 1 ;如果商 严格小于 -231 ,则返回 -231 。
示例 1:
输入: dividend = 10, divisor = 3 输出: 3 解释: 10/3 = 3.33333.. ,向零截断后得到 3 。
示例 2:
输入: dividend = 7, divisor = -3 输出: -2 解释: 7/-3 = -2.33333.. ,向零截断后得到 -2 。
提示:
-231 <= dividend, divisor <= 231 - 1divisor != 0
解法
方法一:模拟 + 快速幂
思考
除法可以看成反复减法,但若每次只从被除数中减去 \(1\) 倍除数、商加 \(1\),当 \(|a|\) 接近 \(2^{31}\) 时循环次数过大,无法通过。题目同时禁止乘法、除法与取余运算。
在剩余量仍够的前提下将除数不断左移加倍,即可一次扣掉 \(2^k\) 倍,商按二进制累加。这与快速幂的思想一致。左移时还需防止溢出:若再翻倍会超出 \(32\) 位范围,则停止倍增。
注意到环境只能存储 \(32\) 位有符号整数,将负数取相反数可能溢出(例如 \(a=-2^{31}\))。因此符号单独记录,运算全程在负数上进行;并特判 \(b=1\),以及 \(a=-2^{31}\) 且 \(b=-1\) 时返回 \(2^{31}-1\)。
除法本质上就是减法,题目要求我们计算出两个数相除之后的取整结果,其实就是计算被除数是多少个除数加上一个小于除数的数构成的。但是一次循环只能做一次减法,效率太低会导致超时,可借助快速幂的思想进行优化。
需要注意的是,由于题目明确要求最大只能使用 32 位有符号整数,所以需要将除数和被除数同时转换为负数进行计算。因为转换正数可能会导致溢出,如当被除数为 INT32_MIN 时,转换为正数时会大于 INT32_MAX。
假设被除数为 \(a\),除数为 \(b\),则时间复杂度为 \(O(\log a \times \log b)\),空间复杂度 \(O(1)\)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |