自学内容网 自学内容网

29. 两数相除

目录

一、问题描述

二、解题思路

三、代码

四、复杂度分析


一、问题描述

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

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

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

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

二、解题思路

  1. 符号处理:首先要确定结果的符号。如果被除数和除数符号相同,则结果为正,否则为负。
  2. 除法通过减法实现:我们可以将除法转换为多次减法的过程,即被除数不断减去除数,直到剩余的部分小于除数为止。但为了提高效率,我们可以通过位移操作,每次将除数进行左移(即乘 2),直到超过被除数。
  3. 加速减法:为了避免每次减去除数都仅减去一个除数,我们通过不断左移除数,以找到一个接近被除数的最大数,然后进行减法,这样能快速逼近商值。
关键步骤:
  1. 处理符号:记录被除数和除数的符号,最后统一处理结果的符号。
  2. 避免溢出:当被除数是 INT_MIN(即 -2^31)且除数是 -1 时,结果会超过 32 位整数的最大值,因此需要提前返回 INT_MAX

三、代码

class Solution {
    public int divide(int dividend, int divisor) {
        // 特殊情况处理:防止溢出
        if (dividend == Integer.MIN_VALUE && divisor == -1) {
            return Integer.MAX_VALUE;
        }

        // 确定结果符号,结果为正或负
        boolean isNegative = (dividend < 0) ^ (divisor < 0);

        // 将被除数和除数转为负数处理,避免溢出(-2^31 转正会溢出)
        dividend = Math.abs(dividend);
        divisor = Math.abs(divisor);

        // 商的计算
        int result = 0;
        while (dividend - divisor >= 0) {
            int temp = divisor;
            int multiple = 1;
            // 将除数左移,直到它大于被除数
            while (dividend - (temp << 1) >= 0) {
                temp <<= 1;
                multiple <<= 1;
            }
            // 从被除数中减去移位后的最大除数
            dividend -= temp;
            // 累加商
            result += multiple;
        }

        // 返回带符号的结果
        return isNegative ? -result : result;
    }
}

四、复杂度分析

  • 时间复杂度:O(logN),其中 N 是被除数的绝对值。由于每次我们通过位移加速减法,减少的速度是指数级的,因此整体时间复杂度较低。
  • 空间复杂度:O(1),只用了常数级别的额外空间。

原文地址:https://blog.csdn.net/weixin_61695887/article/details/142833932

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!