【力扣刷题记 29】——《两数相除》

204 阅读3分钟

Offer 驾到,掘友接招!我正在参与 2022 春招打卡活动,点击查看活动详情

一、题目描述:

  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。

二、题目和思路分析:

要求不适用乘法,除法和mod运算符(取余),也好像不是很难的样子,毕竟还可以用+-嘛!

那么怎么想想呢?用加减法来实现除法,好像也不是特别复杂,毕竟乘除法本身就是加减法的进阶而已。

稍微一想,就会想到:

被除数减去除数,得到的值大于除数的话,再减去除数,直到小于除数,计减去的次数。

这样一个个减,可能有些慢,那么有没有快一些的方法呢?或者说在减的基础上如何优化呢?

可以两个两个的减,如果发现超了,反过来再加一个对比一下。

不过这样想想也没什么技术难度,翻开评论区看看各位大神的想法,才知道大佬们都是用位运算搞定的。

可是使用位运算,本质上不也是使用了乘法嘛!并且如果我不看评论区,永远想不到还能这么做,哼,我想不到的方法算什么好方法?

评论区是靠不住的,还是要靠自己!

一个个减或者两个两个减,还是会超时,那么如果每次让除数翻一倍呢?

这样想起来运算量就会少很多,当前的除数如果大于被除数,直接返回0。否则的话,就进行循环判断,只要当前除数加自身还是小于被除数,那么除数就再次翻倍,同时记录除数翻倍次数作为加的记录。

逻辑没得问题,代码调试起来!

三、代码:

代码实现如下:

/**
 * @param {number} dividend
 * @param {number} divisor
 * @return {number}
 */
var divide = function(dividend, divisor) {

    let p = true // Positive默认商为正数
    if((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0)){ // 如果除数与被除数正负相反,结果为负数
        p = false
    }

    dividend = Math.abs(dividend)
    divisor = Math.abs(divisor)

    let res = fun(dividend, divisor)

    p || (res = -res)

    return (res > 2147483647) ? 2147483647 : res

    function fun (a, b){
        if (a < b) return 0 // 当 被除数<除数 时返回0
        let cnt = 1 // 记录目前相加的是几个除数
        let temp = b // 除数赋值给temp
        while ((temp + temp) < a) { // 如果两个除数相加还是小于被除数
            cnt = cnt + cnt // 记录数也相应翻倍
            temp = temp + temp // 除数翻倍
        } 
        // 此时temp为b的cnt倍,并且temp小于a,所以继续循环遍历a - temp, b即可。

        return cnt + fun(a - temp, b) // 继续以上一个余下的值,和除数代入方法循环
    }


};

四、总结:

这道题还是很有意思的,位运算解题在我看来明显又复杂又违反规则,我写的这种方法才是真正的解题方法!

加油吧!

image.png