「leetcode」29.两数相除

原题

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。git

返回被除数 dividend 除以除数 divisor 获得的商。github

示例 1:bash

输入: dividend = 10, divisor = 3
输出: 3
复制代码

示例 2:ide

输入: dividend = 7, divisor = -3
输出: -2
复制代码

说明:ui

  • 被除数和除数均为 32 位有符号整数。
  • 除数不为 0。
  • 假设咱们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31,  2^31 − 1]。本题中,若是除法结果溢出,则返回 231 − 1。

思路

解题思路来自评论区的foxleezh大神。题目中明确不能使用/, 咱们能够右移模拟除法,右移能够等价于下面的等式spa

  • 右移1位,等价于,除以2的1次方。
  • 右移2位,等价于,除以2的2次方。
  • 右移3位,等价于,除以2的3次方。
a / 2 === a >> 1
a / 4 === a >> 2
a / 8 === a >> 3
复制代码

被除数 / 除数 === 商……余数 等价于 ➡️ 被除数 === (商 * 除数) + 余数 等价于 ➡️ (被除数 - 余数) / 商 === 除数code

假设,咱们的被除数等于100,除数等于5。get

根据等式(被除数 - 余数) / 商 == 除数,咱们首先要找到,100除以多少最接近于除数(或者说,除以多少时会大于等于除数)。it

当100除以2^31时,结果相较于除数会很是的小。咱们使用循环逐渐减小右移的位数,逐渐逼近除数,当100 >>> 4(100 / 16)时等于6,大于等于5。io

这时,咱们能够确定**商是大于16(2的四次方)**的某个数(或者说,100至少包含16个5)。

咱们使用被除数 = 被除数 - 16 * 除数等于还剩下的没有除干净的数。目前还剩下20。咱们再次使用上述的方法,再次逼近除数(获取20里还有几个5)。最终获得最后的结果。

代码

/** * @param {number} dividend * @param {number} divisor * @return {number} */
var divide = function(dividend, divisor) {
    
    // 判断结果是否为负数
    const isNegative = (dividend ^ divisor) < 0
    
    // 统一按正数处理
    dividend = Math.abs(dividend)
    divisor = Math.abs(divisor)
    
    if (dividend === 0) {
        return 0
    }
    
    if (dividend === 2147483648 && divisor === 1) {
        // 避免结果溢出
        return isNegative ? -dividend/divisor : dividend/divisor - 1
    }
    
    let result = 0
    
    for (let i = 31; i >= 0; i--) {
        // 注意这里须要使用无符号右移
        if ((dividend >>> i) >= divisor) {
            result += Math.pow(2, i)
            dividend -= Math.pow(2, i) * divisor
        }
    }
    
    return isNegative ? -result : result
};
复制代码
相关文章
相关标签/搜索