Divide Two Integers

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来考,还是需要好好掌握的。

你可能感兴趣的:(Integer)