0029. Divide Two Integers (M)

Divide Two Integers (M)

题目

Given two integers dividend and divisor, divide two integers without using multiplication, division and mod operator.

Return the quotient after dividing dividend by divisor.

The integer division should truncate toward zero.

Example 1:

Input: dividend = 10, divisor = 3
Output: 3

Example 2:

Input: dividend = 7, divisor = -3
Output: -2

Note:

  • Both dividend and divisor will be 32-bit signed integers.
  • The divisor will never be 0.
  • Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: ([−2^{31}, 2^{31} − 1]). For the purpose of this problem, assume that your function returns (2^{31} − 1) when the division result overflows.

题意

在不使用乘法、除法、取模操作的前提下,实现除法。若得到的商溢出Integer的范围,则返回Integer的最大值。

思路

首先要明确正负数除法的规则,经过实验可得Java的规则是使得到的商尽可能接近0(即直接省去得到的负数商的小数部分),说明商与除数的乘积的绝对值小于等于被除数的绝对值,在这个基础上实现除法的算法。

最直接的做法是让被除数挨个减去(若正负数除法则为加上)除数,复杂度为(O(N))但在商的绝对值很大的情况下会超时。

更高效方法的大致方向是:将除数和被除数都化为绝对值后,倍增除数,找到比被除数小的那个值,记录倍增的次数n,(2^n)即是所求的商,复杂度为(O(logN))。(当然具体实现更加复杂)

因为题目要求环境只能存储int范围的值,所以不使用long,也不使用与乘除相似的位运算,具体操作直接看代码。


代码实现

Java

class Solution {
    public int divide(int dividend, int divisor) {
        // 只有这一种情况会造成商溢出,先处理掉
        if (dividend == Integer.MIN_VALUE && divisor == -1) {
            return Integer.MAX_VALUE;
        }

        // 记录商的正负值
        boolean isMinus = ((dividend < 0) != (divisor < 0));
        
        // 如果除数或被除数中有一个是Integer.MIN_VALUE,那么取绝对值就会溢出
        // 所以全部转化为负数进行处理
        dividend = dividend > 0 ? -dividend : dividend;
        divisor = divisor > 0 ? -divisor : divisor;
		
        // 如果被除数已经比除数大(因为全是负数),商只可能为0
        if (dividend > divisor) {
            return 0;
        }

        int quotient = 1;		// 商的绝对值
        int d = divisor;		// 当前需要在除数上累加的值
        int sum = divisor;		// 累加后的除数
        int count = 1;			// 当前累加值对应的divisor个数,d = count * divisor

        while (true) {
            // 当累加后的除数绝对值仍小于等于被除数时,则进行累加
            // sum + d < 0 的判断是为了防止sum+d后溢出
            if (sum + d < 0 && sum + d >= dividend) {
                sum += d;				// 将待加值累加到除数上
                d += d;					// 待加值自我累加
                quotient += count;		// 更新商
                count += count;			
            } else {
                // 当且仅当加上待加值后的除数绝对值大于被除数,且待加值正好为最原始除数时才跳出
                // 因为这时累加后的除数已经达到小于等于被除数的最大值,多加一个除数都不行
                if (d == divisor) {
                    break;		
                } else {
                    // 重置待加值,以尽可能使累加除数的绝对值接近被除数
                    d = divisor;
                    count = 1;
                }
            }
        }
		
        // 最后注意商的正负号
        return isMinus ? -quotient : quotient;
    }
}

JavaScript

/**
 * @param {number} dividend
 * @param {number} divisor
 * @return {number}
 */
var divide = function (dividend, divisor) {
  if (dividend === -Math.pow(2, 31) && divisor === -1) {
    return Math.pow(2, 31) - 1
  }
  let isMinus = dividend < 0 !== divisor < 0
  dividend = Math.abs(dividend)
  divisor = Math.abs(divisor)
  let quotient = 0
  let count = 1
  let curDiv = divisor

  while (dividend >= divisor) {
    if (dividend >= curDiv) {
      dividend -= curDiv
      quotient += count
      count += count
      curDiv += curDiv
    } else {
      curDiv = divisor
      count = 1
    }
  }

  return isMinus ? -quotient : quotient
}

------------恢复内容结束------------

原文地址:https://www.cnblogs.com/mapoos/p/13185657.html