[LeetCode] 29. Divide Two Integers 两数相除

 

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

The integer division should truncate toward zero, which means losing its fractional part. For example, 8.345 would be truncated to 8, and -2.7335 would be truncated to -2.

Return the quotient after dividing dividend by divisor.

Note: Assume we are dealing with an environment that could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. For this problem, if the quotient is strictly greater than 2^31 - 1, then return 2^31 - 1, and if the quotient is strictly less than -2^31, then return -2^31.

Example 1:

Input: dividend = 10, divisor = 3
Output: 3
Explanation: 10/3 = 3.33333.. which is truncated to 3.

Example 2:

Input: dividend = 7, divisor = -3
Output: -2
Explanation: 7/-3 = -2.33333.. which is truncated to -2.

Constraints:

  • -2^31 <= dividend, divisor <= 2^31 - 1
  • divisor != 0

 

这道题让我们求两数相除,而且规定不能用乘法,除法和取余操作,那么这里可以用另一神器位操作 Bit Manipulation,思路是,如果被除数大于或等于除数,则进行如下循环,定义变量t等于除数,定义计数p,当t的两倍小于等于被除数时,进行如下循环,t扩大一倍,p扩大一倍,然后更新 res 和m。这道题的 OJ 给的一些 test case 非常的讨厌,因为输入的都是 int 型,比如被除数是 -2147483648,在 int 范围内,当除数是  -1 时,结果就超出了 int 范围,需要返回 INT_MAX,所以对于这种情况就在开始用 if 判定,返回 INT_MAX。然后还要根据被除数和除数的正负来确定返回值的正负,这里采用长整型 long 来完成所有的计算,最后返回值乘以符号即可。其实这道题的本质还是不停的成倍数扩大除数,虽然题目说了不能用乘法,但是这里用了位操作的左移来巧妙地规避了这一点,因为左移一位就相当于乘以2。

这里的外层 while 循环是判断被除数大于等于除数,然后里面定义了个临时变量t,初始化为除数n,还有表示临时商的p,初始化为1。内层的 while 循环就是通过不停扩大除数,来找到临时商的最大值,比如若被除数 m=56,除数 n=5 的话,此时经过内层 while 循环后,t=40,p=8,此时t再翻倍的话,就会超过被除数了,所以就到这里,然后更新结果 res 和被除数m的值。下一轮循环时被除数 m=16,除数 n=5,此时经过内层 while 循环后,t=10,p=2,此时t再翻倍的话,就会超过被除数了,所以就到这里,然后更新结果 res 和被除数m的值。下一轮循环时被除数 m=6,除数 n=5,此时经过内层 while 循环后,t=5,p=1,此时t再翻倍的话,就会超过被除数了,所以就到这里,然后更新结果 res 和被除数m的值。这时候被除数 m=1,除数 n=5,被除数小于除数了,跳出外层 while 循环,返回结果 res=11 即可,参见代码如下:

 

解法一:

class Solution {
public:
    int divide(int dividend, int divisor) {
        if (dividend == INT_MIN && divisor == -1) return INT_MAX;
        long m = labs(dividend), n = labs(divisor), res = 0;
        int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;
        if (n == 1) return sign == 1 ? m : -m;
        while (m >= n) {
            long t = n, p = 1;
            while (m >= (t << 1)) {
                t <<= 1;
                p <<= 1;
            }
            res += p;
            m -= t;
        }
        return sign == 1 ? res : -res;
    }
};

 

我们可以通过递归的方法来解使上面的解法变得更加简洁:

 

解法二:

class Solution {
public:
    int divide(int dividend, int divisor) {
        long m = labs(dividend), n = labs(divisor), res = 0;
        if (m < n) return 0;
        long t = n, p = 1;
        while (m >= (t << 1)) {
            t <<= 1;
            p <<= 1;
        }
        res += p + divide(m - t, n);
        if ((dividend < 0) ^ (divisor < 0)) res = -res;
        return res > INT_MAX ? INT_MAX : res;
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/29

 

参考资料:

https://leetcode.com/problems/divide-two-integers/

https://leetcode.com/problems/divide-two-integers/discuss/13524/summary-of-3-c-solutions

https://leetcode.com/problems/divide-two-integers/discuss/13407/C%2B%2B-bit-manipulations

https://leetcode.com/problems/divide-two-integers/discuss/142849/C%2B%2BJavaPython-Should-Not-Use-%22long%22-Int

 

LeetCode All in One 题目讲解汇总(持续更新中...)

posted @ 2015-04-16 14:04  Grandyang  阅读(31787)  评论(25编辑  收藏  举报
Fork me on GitHub