题目要求我们用一个32位整数整除另外一个整数,但是不允许我们使用除法,乘法和取模运算。


有趣的问题,下面说一下我的思路:

首先,先给出两个正整数除法运算的过程。假设a为被除数,而b为除数。在计算机中无符号整数除法div可以用下面的数学公式来表示:

即计算机除法中的a/b实际上是数学意义上a/b代表的有理数向下取整值。可以换一个方法来等价表示上面公式:

因此我们只需要能找到一个值c,满足下面条件即可:

但是我们不能从1到正无穷枚举c,因为如果a足够大且b足够小,那么c的值可能要上亿,上亿次的枚举消耗的时间非常可怕。但是我们不能使用乘法又该如何快速增大枚举值呢。这源于一个思路,v[0]=1,v[1]=v[0]+v[0],...,v[n]=v[n-1]+v[n-1]。发现了吗,v[i]=2^i,而32位整数绝对不会超过v[32],因此我们可以快速的利用v数组快速逼近c。

实际做法如下:

v and u are arrays with size 32

v[0] = 1, u[0] = b

limit = 0

for(; u[limit] < a; limit = limit + 1)

  u[limit  + 1] = u[limit ] + u[limit ]

  v[limit + 1] = v[limit] + v[limit]

这样我们就得到一个数组u,并且保证了u[0], ..., u[limit - 1] < a,且u[limit] >= a,实际上u[i] = b * 2^i。但是我们又该如何能够借助这样一个数组u计算出最终的c?

由于每个整数在计算机中都是由二进制表示而成,因此c必然等于2^i1+2^i2+...+2^in,其中i1,...in互不相同并按增序排序。因此我们所要找的实际上是这样一组i1,i2,...,in。由于2^n=1+2^0+2^1+2^2+...+2^(n-1),因此我们能得知2^in>2^i1+2^i2+...+2^in-1,换句话说有2^in<=c<2^(in+1),等价的形式为u[in]=b*2^in<=b*c=a<b*2^(in+1)=u[in+1]。到了这一步我们就知道如何快速地决定in,而对于in-1的计算,可以通过u[in-1]=b*2^in-1<=b*(c-2^in)=a-u[in]<b*2^(in-1+1)=u[in-1+1]得出,推理过程如上。这样不断地计算下去,我们就可以将i1,i2,...,in全部计算出来。

用代码展示上面的结论:

r = a, c = 0

for(i = limit; r >= b; i--)

  if(u[i] <= r)

    r = r - u[i]

    c = c + v[i]

综合上面我们已经得到了计算两个正整数的方式。上面这个算法的时间复杂度与空间复杂度均为常数O(1),因为不存在与输入相关联的冗余循环。

对于a,b均为负数的除法,有a/b=(-a)/(-b),因此可以直接用上述正整数除法的运算方式。对于a为负数的运算。计算机中对于带一个负数除法ndiv的定义如下:

但是我们不希望为带负数的重新定义一个新的算法,故我们要使用下面公式提供的计算c的方法:

故到了这里问题全面解决。当然这只是理论上的,实践上还会存在数值超出32位整数表示范围的情况,这需要读者自己对特殊情况进行处理。


最后提供一下AC代码,主要是需要对Integer.MIN_VALUE和越界做处理:

 package cn.dalt.leetcode;

 /**
  * Created by dalt on 2017/6/21.
  */
 public class DivideTwoIntegers {
     public int divide(int dividend, int divisor) {
         if (divisor == 0) {
             throw new ArithmeticException();
         }
         if (divisor == Integer.MIN_VALUE) {
             return dividend == Integer.MIN_VALUE ? 1 : 0;
         }
         if (dividend == Integer.MIN_VALUE) {
             if (divisor == -1) {
                 return Integer.MAX_VALUE;
             }
             if (divisor == 1) {
                 return Integer.MIN_VALUE;
             }
             if (divisor < 0) {
                 return divide(dividend - divisor, divisor) + 1;
             }
             return divide(dividend + divisor, divisor) - 1;
         }
         if (divisor < 0) {
             return divide(-dividend, -divisor);
         }
         if (dividend < 0) {
             return -divide(-dividend, divisor);
         }
         return div(dividend, divisor);
     }

     /**
      * Calculate floor(a/b)
      *
      * @param a a positive number
      * @param b a positive number
      * @return floor(a/b)
      */
     public int div(int a, int b) {
         int[] v = new int[32];
         int[] u = new int[32];
         v[0] = 1;
         u[0] = b;
         int limit = 0;
         for (; u[limit] <= a && u[limit] > 0; limit++) {
             u[limit + 1] = u[limit] + u[limit];
             v[limit + 1] = v[limit] + v[limit];
         }
         int c = 0;
         int r = a;
         for (limit--; r >= b; limit--) {
             if (r >= u[limit]) {
                 c += v[limit];
                 r -= u[limit];
             }
         }
         return c;
     }
 }

Leetcode:Divide Two Integers分析和实现的更多相关文章

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

    Divide two integers without using multiplication, division and mod operator. If it is overflow, retu ...

  2. LeetCode: Divide Two Integers 解题报告

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

  3. Leetcode Divide Two Integers

    Divide two integers without using multiplication, division and mod operator. 不用乘.除.求余操作,返回两整数相除的结果,结 ...

  4. [LeetCode] Divide Two Integers( bit + 二分法 )

    Divide two integers without using multiplication, division and mod operator. 常常出现大的负数,无法用abs()转换成正数的 ...

  5. leetcode Divide Two Integers python

    class Solution(object): def divide(self, dividend, divisor): """ :type dividend: int ...

  6. leetcode面试准备:Divide Two Integers

    leetcode面试准备:Divide Two Integers 1 题目 Divide two integers without using multiplication, division and ...

  7. [Leetcode][Python]29: Divide Two Integers

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 29: Divide Two Integershttps://oj.leetc ...

  8. leetcode第28题--Divide Two Integers

    Divide two integers without using multiplication, division and mod operator. 分析:题目意思很容易理解,就是不用乘除法和模运 ...

  9. 【一天一道LeetCode】#29. Divide Two Integers

    一天一道LeetCode系列 (一)题目 Divide two integers without using multiplication, division and mod operator. If ...

随机推荐

  1. (三)js循环结构

    1.循环结构 a)    当循环 语法:while(condition){         code...     }     do(){         code...     } while(); ...

  2. header("Location:http://www.baidu.com");

    php 中的跳转函数 header("Location:http://www.baidu.com"); 但是一定要放在文件的开头   不允许有任何输出. 否则在之前添加  ob_s ...

  3. 接口测试基础——第5篇xlrd模块

    读取Excel表格中的内容,不多说,直接上代码: # coding: utf-8 import xlrd # excel路径 excel_path = r'C:\Users\weiming\Deskt ...

  4. 数据库连接配置 app.config web.config

    通过ADO.Net连接程序和SQLServer数据库的连接字符串: connectionString ="server=(local);database=Demo;integrated se ...

  5. yii 操作cookie

    原文地址:http://blog.sina.com.cn/s/blog_664c9f650100yqkn.html 设置cookie: $cookie = new CHttpCookie('mycoo ...

  6. javabrideg的使用实践

    (1)进入这个网站http://sourceforge.net/projects/php-java-bridge/files,选择Binary package,然后选择最新的版本Php-java-br ...

  7. bzoj 4671 异或图——容斥+斯特林反演+线性基

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671 考虑计算不是连通图的方案,乘上容斥系数来进行容斥. 可以枚举子集划分(复杂度是O(Be ...

  8. 归并排序的JavaScript实现

    思想 这是一种分治算法.将原始数组切分成较小的数组,直到每个小数组只有一项,然后在将小数组归并为排好序的较大数组,直到最后得到一个排好序的最大数组. 代码 function mergeSort(arr ...

  9. 解决Maven提示:Could not read settings.xml, assuming default values

    本文转载自:http://blog.csdn.net/hqocshheqing/article/details/47702049 最近在学习Maven  时总是出现 Could not read se ...

  10. 【转】Jenkins+Ant+Jmeter自动化性能测试平台

    Jmeter是性能测试的工具,java编写.开源,小巧方便,可以图形界面运行也可以在命令行下运行.网上已经有人使用ant来运行,,既然可以使用ant运行,那和hudson.jenkins集成就很方便了 ...