剑指offer T1 整数除法

题目

输入两个int型整数,求它们除法的商,要求不得使用乘号’*’、除号’/‘以及求余符号’%’。当发生溢出时返回最大的整数值。假设除数不为0。例如,输入15和2,输出15/2的结果,即7。

解题思路:
当被除数大于除数时,继续比较判断被除数是否大于除数的2倍,如果是,则继续判断被除数是否大于除数的4倍、8倍等。如果被除数最多大于除数的2k倍,那么将被除数减去除数的2k倍,然后将剩余的被除数重复前面的步骤。由于每次将除数翻倍,因此优化后的时间复杂度是O(logn)。

下面以15/2为例讨论计算的过程。15大于2,也大于2的2倍(即4),还大于2的4倍(即8),但小于2的8倍(即16)。于是先将15减去8,还剩余7。由于减去的是除数的4倍,减去这部分对应的商是4。接下来对剩余的7和除数2进行比较,7大于2,大于2的2倍(即4),但小于2的4倍(即8),于是将7减去4,还剩余3。这一次减去的是除数2的2倍,对应的商是2。然后对剩余的3和除数2进行比较,3大于2,但小于2的2倍(即4),于是将3减去2,还剩余1。这一次减去的是除数的1倍,对应的商是1。最后剩余的数字是1,比除数小,不能再减去除数了。于是15/2的商是4+2+1,即7。

上述讨论假设被除数和除数都是正整数。如果有负数则可以将它们先转换成正数,计算正数的除法之后再根据需要调整商的正负号。例如,如果计算-15/2,则可以先计算15/2,得到的商是7。由于被除数和除数中有一个负数,因此商应该是负数,于是商应该是-7。
将负数转换成正数存在一个小问题。对于32位的整数而言,最小的整数是-231,最大的整数是231-1。因此,如果将-231转换为正数则会导致溢出。由于将任意正数转换为负数都不会溢出,因此可以先将正数都转换成负数,用前面优化之后的减法计算两个负数的除法,然后根据需要调整商的正负号。
最后讨论可能的溢出。由于是整数的除法并且除数不等于0,因此商的绝对值一定小于或等于被除数的绝对值。因此,int型整数的除法只有一种情况会导致溢出,即(-231)/(-1)。这是因为最大的正数为231-1,231超出了正数的范围。

参考代码:

package 剑指offer;

public class t1整数除法 {
    public static int divide(int dividend, int divisor){
        /**
         * 0x80000000为最小的int型整数,-2 31次方,
         * 0xc0000000为它的一半  -2的30次方,
         * dividend 被除数 divisor 除数
         */

        //如果被除数是最大值,除数是一 这个就是2 31次方 但是这样会溢出
        if (dividend == 0x80000000 && divisor ==-1){
            return Integer.MAX_VALUE;
        }
        //这个negative是为了给被除数 除数做标记的
        /**
         *     如果negative是等于0的说明是 被除数和除数都是大于0的
         *     如果negative是等于1的说明是 有一个是负数,那么 result要取-
         */
        int negative =2;
        //把正的统统变成负的
        if(dividend>0){
            negative--;
            dividend=-dividend;
        }
        if(divisor>0){
            negative--;
            divisor=-divisor;
        }
        //这是执行除法的核心
        int result =divideCore(dividend,divisor);
        /**
         * 这里是 当negative==1时,执行冒号前面的-result
         * 当不是的时候,执行冒号后面的result
         */
        return negative==1 ? -result : result;
    }

    //执行两数除法的算法

    /**
     *
     * @param dividend
     * @param divisor
     * @return
     *
     * result 就是结果
     * quotient是倍数 如2的4次方 就是4
     * value是真实的值  如2的4次方 就是16;每次执行时都会divudend-value
     *
     */
    private static int divideCore(int dividend, int divisor){
        int result =0;
        //当除数比被除数小就执行循环(因为是负数所以是大)
        while (dividend <= divisor) {
            //把除数给value
            int value =divisor;
            //一开始倍数是一
            int quotient=1;
            //value 是
            while (value >= 0xc0000000 && dividend<=value+value){
                quotient+=quotient;
                //因为是2 K次方 所以要value+value
                value+=value;
            }
            result+=quotient;
            dividend-=value;
        }
        return result;
    }

    public static void main(String[] args){

        System.out.println(divide(15,2));
    }


}

你可能感兴趣的:(leetcode,算法,职场和发展)