【算法训练】LeetCode#29 两数相除

一、描述

29. 两数相除

给你两个整数,被除数 dividend 和除数 divisor。将两数相除,要求 不使用 乘法、除法和取余运算。

整数除法应该向零截断,也就是截去(truncate)其小数部分。例如,8.345 将被截断为 8-2.7335 将被截断至 -2

返回被除数 dividend 除以除数 divisor 得到的

注意:假设我们的环境只能存储 32 位 有符号整数,其数值范围是 [-2147483648, 2147483647] 。本题中,如果商 严格大于 2147483647 ,则返回 2147483647 ;如果商 严格小于 -2147483648 ,则返回 -2147483648

示例 1:

输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = 3.33333.. ,向零截断后得到 3 。

示例 2:

输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = -2.33333.. ,向零截断后得到 -2 。

二、思路

不允许使用除法模拟除法,那应该是用减法做吧,但是看了眼数值范围,感觉可能会越界,不过先试一试吧。

显然不行,减法是可以得到结果的,但是循环次数太多了,看了一眼讨论,发现了一个可行方案,还是自己太菜。

虽然题中不允许使用乘法和除法,但是没有限制移位运算,因此可以通过左移右移的方式对结果进行逼近,然后再辗转相减。

三、解题


public class LeetCode29 {
    public static void main(String[] args) {
        System.out.println(divide(7,-3));
    }

    public static int divide(int dividend, int divisor) {
        int ans = 0;
        if (divisor == 0){
            return 0;
        }
        int right = 2147483647;
        int left = -2147483648;
        if (dividend == left && divisor == -1){
            return 2147483647; // 最坏结果
        }

        boolean flag = (dividend ^ divisor) < 0; // 判断是否异号
        long dividendL = Math.abs((long)dividend);
        long divisorL = Math.abs((long)divisor);
        for (int i = 31 ; i >= 0 ; i--){
            // 结果最大不超过2^31,因此从2^31开始尝试
            if ( (dividendL>>i) >= divisorL){
                // 当 dividend/2^i >= divisor时,2^i*divisor一定小于dividend,因此相减
                dividendL -= divisorL<<i;
                ans += 1<<i; // 2^i一定是组成结果的一部分
            }
        }
        return flag ? -ans : ans;
    }
}


posted @ 2023-03-07 11:54  小拳头呀  阅读(38)  评论(0编辑  收藏  举报