题目要求我们用一个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. 在Linux上部署DotNet Core项目的时候发现Apache无法转发Kestrel的5000端口的问题

    CentOS服务器上使用Apache托管Dotnet Core2,服务启动了,端口也打开了.在本地使用curl命令可以访问5000端口的网页内容,但是访问Apache的端口却无法获取到网页的内容.想起 ...

  2. ORACLE PL/SQL编程之触发器

    8.1 触发器类型 8.1.1 DML触发器 8.1.2 替代触发器 8.1.3 系统触发器 8.2 创建触发器 8.2.1 触发器触发次序 8.2.2 创建DML触发器 8.2.3 创建替代(INS ...

  3. 排序算法总结(C#版)

    算法质量的衡量标准: 1:时间复杂度:分析关键字比较次数和记录的移动次数: 2:空间复杂度:需要的辅助内存: 3:稳定性:相同的关键字计算后,次序是否不变. 简单排序方法 .直接插入排序 直接插入排序 ...

  4. Maven打包同一个jar有不同的:版本+时间戳(解决思路)

    在我们的开发过程中,目前流行的版本控制工具maven,在项目开发阶段,大家都是通过发布SNAPSHOT快照版进行相互模块之间的依赖开发, 这个时候就会有一个问题,要是一天构建多次的快照版,会发现在项目 ...

  5. java图形化界面-------鼠标监听画圆----------使用匿名类

    package com.aa; import java.awt.Color; import java.awt.Graphics; import java.awt.event.MouseAdapter; ...

  6. 方格取数(dp)

    方格取数 时间限制: 1 Sec  内存限制: 128 MB提交: 9  解决: 4[提交][状态][讨论版][命题人:quanxing] 题目描述 设有N×N的方格图,我们在其中的某些方格中填入正整 ...

  7. PHP手机号中间四位用星号*代替显示

    三种实现方式 <?php $tel = '12345678910'; //1.字符串截取法 $new_tel1 = substr($tel, 0, 3).'****'.substr($tel, ...

  8. 接口规范,js处理json,php返回给ajax的数据格式

    ajax异步获取php数据. 一般php会在后台处理请求,并返回结果给前端. 必须是echo的方式,不然ajax获取不到. 返回的类型包括,字符串,数字,json. 最常用的就是json. 返回后,前 ...

  9. JAVA 比较两个日期相差的天数

    在实际的应用中,我们经常会比较两个日期相差的天数,下面我们通过java方法判断两个日期所差的额天数. 具体内容,请看下面的代码: package com.jd.jr.fclient.test; imp ...

  10. VC++使用TCHAR

    #ifdef _UNICODE #define tcout wcout #define tcin wcin #else #define tcout cout #define tcin cin #end ...