码迷,mamicode.com
首页 > 其他好文 > 详细

Divide Two Integers

时间:2015-03-14 15:13:58      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:

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

Divide two integers without using multiplication, division and mod operator.

If it is overflow, return MAX_INT.

解题思路:

很讨厌做这种类型的题目,一来不熟悉,二来要注意的地方很多,比如溢出问题,计数的边界,只能硬着头皮上。题目要求不能使用乘法、除法和mod运算,来实现除法。那就只有用加法和减法了,(后来发现还有位运算,其实就是除以2和乘以2)。

先写了个最简单的,只考虑了正负问题,然后用被除数一直减去除数,只到被除数小于除数,减了多少次就是商了。当然不可能对,一定会超时。

public class Solution {
    public int divide(int dividend, int divisor) {
        int isNegative = 1;
        if(dividend < 0){
            dividend = -dividend;
            isNegative = -isNegative;
        }
        if(divisor < 0){
            divisor = -divisor;
            isNegative = -isNegative;
        }
        if(divisor == 0){
            return Integer.MAX_VALUE;
        }
        int result = 0;
        
        while(dividend >= divisor){
            dividend = dividend - divisor;
            result++;
        }
        return isNegative < 0 ? -result : result;
    }
}

然后又写了个改进版的。因为任何数字都可以表示为以10为底的N次多项式的和,即x= a1*10^n + a2*10^n-1+...+an*10^1+an+1*10^0。所以可以把被除数一直乘以10,到达被除数的位置,再开始用上面的方法计算。比如计算500/2,不必要像上面那样一直500-2计算次数。而是首先算500-200的次数,然后用剩下的100算100-20的次数,结果就是25了。

public class Solution {
    public int divide(int dividend, int divisor) {
        int result = 0;

        if(divisor == 0){
            return Integer.MAX_VALUE;
        }
        
        if(divisor == Integer.MIN_VALUE){
            if(dividend == Integer.MIN_VALUE){
                return 1;   //-2147483648 / -2147483648 = 1
            }else{
                return 0;   // x / -2147483648 = 0;
            }
        }
        //-2147483648 / -1 = 2147483648溢出
        if(dividend == Integer.MIN_VALUE && divisor == -1){
            return Integer.MAX_VALUE;
        }
        //-2147483648 / x变化成2147483648 / x会溢出,所以先处理掉一次divisor,结果最后加上这个1
        int last = 0;
        if(dividend == Integer.MIN_VALUE){
            dividend += Math.abs(divisor);
            last = 1;
        }
        
        int isNegative = 1;
        if(dividend < 0){
            dividend = -dividend;
            isNegative = -isNegative;
        }
        if(divisor < 0){
            divisor = -divisor;
            isNegative = -isNegative;
        }
        
        int digit = 0;
        //先从最高位算起,除数一直乘以10会溢出,比如2147483647 / 1,只能乘到倒数第二次
        while(dividend / 10 >= divisor){
            divisor *= 10;
            digit++;
        }
        
        while(digit >= 0){
            int temp = 0;   //当前位的结果
            while(dividend >= divisor){
                dividend = dividend - divisor;
                temp++;
            }
            divisor /= 10;  //算下一位的结果,除数要除以10
            result = result * 10 + temp;
            digit--;
        }
        result += last;
        return isNegative < 0 ? -result : result;
    }
}

上面的方法,最关键的是各种溢出值得处理,因为Integer.MIN_VALUE=-2147483648,而Integer.MAX_VALUE=2147483647,绝对值是要小1的。所以处理除数或者被除数为MIN_VALUE的时候,会遇到很多问题。比如,-2147483648作为除数去除任何数,都为0,除了-2147483648/-2147483648=1.

而-2147483648除以任何数字,将他变为2147483648的时候都会溢出,所以只能用它先减去一次除数的绝对值,再处理。等所有的结果都算出来,最后再加上这个1。

当然上面的方法是不允许的,虽然结果AC,因为题目不能用乘法。

后来看了网友的解法,用位运算即可解决了。因为一个数字可以写成10进制的,也能写成2进制的,就是以2为底的多项式的和。所以向左移位(<<)其实就是乘以2,向右移位(>>)其实就是除以2。这样等于用位运算实现了乘除法。上面的解法里,只要把所有的除以10改为>>1,乘以10改为<<1,就可以了。

最后要注意的是,位运算的优先级比加减法还低,所以一定要加括号。

public class Solution {
    public int divide(int dividend, int divisor) {
        int result = 0;

        if(divisor == 0){
            return Integer.MAX_VALUE;
        }
        
        if(divisor == Integer.MIN_VALUE){
            if(dividend == Integer.MIN_VALUE){
                return 1;   //-2147483648 / -2147483648 = 1
            }else{
                return 0;   // x / -2147483648 = 0;
            }
        }
        //-2147483648 / -1 = 2147483648溢出
        if(dividend == Integer.MIN_VALUE && divisor == -1){
            return Integer.MAX_VALUE;
        }
        //-2147483648 / x变化成2147483648 / x会溢出,所以先处理掉一次divisor,结果最后加上这个1
        int last = 0;
        if(dividend == Integer.MIN_VALUE){
            dividend += Math.abs(divisor);
            last = 1;
        }
        
        int isNegative = 1;
        if(dividend < 0){
            dividend = -dividend;
            isNegative = -isNegative;
        }
        if(divisor < 0){
            divisor = -divisor;
            isNegative = -isNegative;
        }
        
        int digit = 0;
        //先从最高位算起,除数一直乘以10会溢出,比如2147483647 / 1,只能乘到倒数第二次
        while(dividend >>1 >= divisor){
            divisor <<= 1;
            digit++;
        }
        
        while(digit >= 0){
            int temp = 0;   //当前位的结果
            while(dividend >= divisor){
                dividend = dividend - divisor;
                temp++;
            }
            divisor >>= 1;  //算下一位的结果,除数要除以10
            result = (result << 1) + temp;  //注意位运算符的优先级很低,不如加法
            digit--;
        }
        result += last;
        return isNegative < 0 ? -result : result;
    }
}

这道题我是没做出来,而且意外处理需要考虑的比较多。但是面试的时候不失为一道比较好的题目,可以用来结合设计test case来考,还是需要好好掌握的。

Divide Two Integers

标签:

原文地址:http://www.cnblogs.com/NickyYe/p/4337497.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!