Leetcode算法Java全解答--29. 两数相除

Leetcode算法Java全解答–29. 两数相除

题目

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

 返回被除数 dividend 除以除数 divisor 得到的商。

 示例 1:

 输入: dividend = 10, divisor = 3
 输出: 3
 示例 2:

 输入: dividend = 7, divisor = -3
 输出: -2
 说明:

 被除数和除数均为 32 位有符号整数。
 除数不为 0。
 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231,  231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。

示例:

 输入: dividend = 10, divisor = 3
     输出: 3
     示例 2:

     输入: dividend = 7, divisor = -3
     输出: -2

想法

  1. 累加被除数,知道大于除数

  2. (网上资源)

任何一个整数可以表示成以2的幂为底的一组基的线性组合,

即num=a_020+a_121+a_222+…+a_n2n。

基于以上这个公式以及左移一位相当于乘以2,

我们先让除数左移直到大于被除数之前得到一个最大的基。

然后接下来我们每次尝试减去这个基,如果可以则结果增加加2^k,然后基继续右移迭代,直到基为0为止。

因为这个方法的迭代次数是按2的幂知道超过结果,所以时间复杂度为O(log(n))。

结果

超过99%的测试案例

时间复杂度/空间复杂度: log n/ 1

总结

代码

我的答案

       /**************************************
     * 题目
     给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

     返回被除数 dividend 除以除数 divisor 得到的商。

     示例 1:

     输入: dividend = 10, divisor = 3
     输出: 3
     示例 2:

     输入: dividend = 7, divisor = -3
     输出: -2
     说明:

     被除数和除数均为 32 位有符号整数。
     除数不为 0。
     假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231,  231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。
     **************************************/

    /**************************************
     *
     * 想法:
     *      1. 累加被除数,知道大于除数
     *
     *    2.(网上资源)  任何一个整数可以表示成以2的幂为底的一组基的线性组合,
     *      即num=a_0*2^0+a_1*2^1+a_2*2^2+…+a_n*2^n。
     *      基于以上这个公式以及左移一位相当于乘以2,
     *      我们先让除数左移直到大于被除数之前得到一个最大的基。
     *      然后接下来我们每次尝试减去这个基,如果可以则结果增加加2^k,然后基继续右移迭代,直到基为0为止。
     *      因为这个方法的迭代次数是按2的幂知道超过结果,所以时间复杂度为O(log(n))。
     *
     * 我的做法
     *      超过99%的测试案例
     *      时间复杂度/空间复杂度:  log n/ 1
     * 代码执行过程:
     *
     * 总结:
     *
     * ***********************************/
    public int divide(int dividend, int divisor) {
        // 相除时溢出处理
        if (divisor == 0 || dividend == Integer.MIN_VALUE && divisor == -1) {
            return Integer.MAX_VALUE;
        }

        // 求符号位
        int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;

        // 求绝对值,为防止溢出使用long
        long dvd = Math.abs((long) dividend);
        long dvs = Math.abs((long) divisor);

        // 记录结果
        int result = 0;

        // 被除数大于除数
        while (dvd >= dvs) {
            // 记录除数
            long tmp = dvs;
            // 记录商的大小
            long mul = 1;

            while (dvd >= (tmp << 1)) {
                tmp <<= 1;
                mul <<= 1;
            }

            // 减去最接近dvd的dvs的指数倍的值(值为tmp)
            dvd -= tmp;

            // 修正结果
            result += mul;
        }

        return result * sign;
    }

大佬们的答案

   public int better(int dividend, int divisor) {
        if (dividend == 0 || divisor == 0) {
            return 0;
        }
        long d1 = dividend, d2 = divisor;
        long result = divideLong(Math.abs(d1), Math.abs(d2));
        result = d1 * d2 < 0 ? -result : result;
        if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
            return Integer.MAX_VALUE;
        }
        return (int) result;
    }
    public long divideLong(long d1,long d2){
        if(d1<d2) {
            return 0;
        }
        long sum=d2,num=1;
        while(sum+sum<=d1){
            sum+=sum;
            num+=num;
        }
        return num+divideLong(d1-sum,d2);
    }

测试用例

 @Test
    public void test029() {
        // 创建测试案例
        int dividend1 = 10;
        int divisor1 = 3;
        int dividend2 = 7;
        int divisor2 = -3;

        int expResult1 = 3;
        int expResult2 = -2;

        Solution029 solution029 = new Solution029();

        int result1 = solution029.divide(dividend1, divisor1);
        int result2 = solution029.divide(dividend2, divisor2);

        Assert.assertEquals(expResult1, result1);
        Assert.assertEquals(expResult2, result2);
    }

其他

代码托管码云地址:https://gitee.com/lizhaoandroid/LeetCodeAll.git

查看其他内容可以点击专栏或者我的博客哈:https://blog.csdn.net/cmqwan

“大佬们的答案” 标签来自leetcode,侵权请联系我进行删改

如有疑问请联系,联系方式:QQ3060507060

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值