题目描述

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

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

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

示例 1:

输入: dividend = 10, divisor = 3

输出: 3

解释: 10/3 = truncate(3.33333..) = truncate(3) = 3

示例 2:

输入: dividend = 7, divisor = -3

输出: -2

解释: 7/-3 = truncate(-2.33333..) = -2

解题思路

首先要考虑到数字的正负问题,如果除数被除数都为正数或者都为负数,结果也是正数,否则为负数。使用 sign 标记正负,然后将除数被除数都转成正数:

int sign = 1;
if ((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0)) {
sign = -1;
}
int dividends = Math.abs(dividend);
int divisors = Math.abs(divisor);

要求不能使用乘法、除法和取余运算,算出两数相除的值,结果值取整。涉及到运算,那就得使用到别的运算符,比如加法。比如 10/3 转成 10 一直减 3,直到被减的数小于被除数。

10 - 3 = 7
7 -3 = 4
4 - 3 = 1 < 3

上面一共减了三次,所以 10/3 = 3,根据思路写出下面代码:

public int divide(int dividend, int divisor) {
int sign = 1;
if ((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0)) {
sign = -1;
}
int dividends = Math.abs(dividend);
int divisors = Math.abs(divisor);
int index = 0;
while (dividends >= divisors) {
dividends = dividends - divisors;
index++;
} return index * sign;
}

结果:

这里涉及到数字范围的问题,我们发现 -2147483648,取相反数还是-2147483648,这是由于编码 int 占四个字节,一个字节八个位。

所以需要使用转成 long 类型,避免数据越界问题:

 int sign = 1;
if ((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0)) {
sign = -1;
}
long dividends = Math.abs((long) dividend);
long divisors = Math.abs((long) divisor);
long index = 0;
while (dividends >= divisors) {
dividends = dividends - divisors;
index++;
}
if (index > Integer.MAX_VALUE && sign == 1) {
return Integer.MAX_VALUE * sign;
}
return (int) index * sign;

结果:

结果超时,是因为一个个减,是需要重复次数,时间复杂度是O(n)。

这里需要使用递进式的减法,比如

10/1 = 10
10 - 1 = 9 index = 1
9 - 1 = 8 index = 2
8 - 1 = 7 index = 3
7 - 1 = 6 index = 4
6 - 1 = 5 index = 5
....
1 - 1 = 0 index = 10

这上面是要进行十步操作,需要做的一个递进的操作,被除数做加倍,比如上面可以转成:

10 - 1= 9          index = 1 = 1
9 - 1*2 = 7 index = 1 + 1*2 = 3
7 - 1*2*2 = 3 index = 1 + 1*2 + 1 *2*2 = 7 再匹配 3 - 1*2*2*2 < 0,还需要再进行上面的减操作
3 - 1 = 2 index = 7 + 1 = 8
2 - 1*2 = 0 index = 7 + 1 + 1* 2 = 10

具体流程:

根据以上思路可得如下代码:

int sign = 1;
if ((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0)) {
sign = -1;
}
long dividends = Math.abs((long) dividend);
long divisors = Math.abs((long) divisor);
long index = 0;
while (dividends >= divisors) {
long temp = divisors;
long i = 1;
while (dividends >= temp) {
dividends = dividends - temp;
index = index + i;
temp = temp << 1;
i = i << 1;
}
}
if (index > Integer.MAX_VALUE && sign == 1) {
return Integer.MAX_VALUE * sign;
}
return (int) index * sign;

总结

  • 此题解法开始想到将除法转成减法,一个一个累计减
  • 需要考虑 int 范围溢出问题,这里统一换成 long 类型
  • 累减需要的时间负复杂度是O(n),容易超时,这里需要转成递进减法,即每次都对被减数加倍

如果觉得文章对你有帮助的话,请点个推荐吧!

【leetcode 29】 两数相除(中等)的更多相关文章

  1. Java实现 LeetCode 29 两数相除

    29. 两数相除 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商 ...

  2. Leetcode 29.两数相除 By Python

    给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 1: 输 ...

  3. LeetCode 29 - 两数相除 - [位运算]

    题目链接:https://leetcode-cn.com/problems/divide-two-integers/description/ 给定两个整数,被除数 dividend 和除数 divis ...

  4. leetcode 29 两数相除

    问题描述 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 ...

  5. [LeetCode]29 两数相除和一个小坑点

    给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 1: 输 ...

  6. LeetCode 29——两数相除

    1. 题目 2. 解答 2.1. 方法一 题目要求不能使用乘法.除法和除余运算,但我们可以将除法转移到对数域. \[ \frac{a}{b} = e^{\frac{lna}{lnb}} = e^{ln ...

  7. leetcode 29两数相除

    我理解本题是考察基于加减实现除法,代码如下: class Solution { public: //只用加减号实现除法, //不用加减号实现除法: int divide(int dividend, i ...

  8. 【剑指 Offer II 001. 整数除法】同leedcode 29.两数相除

    剑指 Offer II 001. 整数除法 解题思路 在计算的时候将负数转化为正数,对于32位整数而言,最小的正数是-2^31, 将其转化为正数是2^31,导致溢出.因此将正数转化为负数不会导致溢出. ...

  9. [LeetCode] 29. Divide Two Integers 两数相除

    Given two integers dividend and divisor, divide two integers without using multiplication, division ...

随机推荐

  1. java变量的初始化之后的默认值

    对于类的成员变量 不管程序有没有显示的初始化,Java  虚拟机都会先自动给它初始化为默认值. 1.整数类型(byte.short.int.long)的基本类型变量的默认值为0. 2.单精度浮点型(f ...

  2. Hadoop - HA学习笔记

    Hadoop HA概述 工作要点 通过双NameNode消除单点故障 元数据管理方式需要改变:内存中各自保存一份元数据:Edits 日志只有 Active 状态的NameNode节点可以做写操作:两个 ...

  3. 针对python输入要求

    针对python输入要求 类型: 1.输入行数不确定,并且每一行输入一个数据. a=[] b=input() while b!='-1': //指随意使用一个值作为一个标志,来进行控制输入的行数.(在 ...

  4. HTML分块

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>菜鸟 ...

  5. 浅谈cache

    2021.9.22更新: <浅谈Cache Memory> http://blog.sina.com.cn/s/blog_6472c4cc0102dusv.html 为什么贴上这个链接呢, ...

  6. C++:用字符串数组实现大数运算,以两个不高于40位的大数运算为例。

    因为基本数据类型中整型的内存范围有限,所以直接进行大数之间的运算,不仅浪费空间,而且运行缓慢,甚至有些会导致数据溢出. 那怎么办呢? 这时我们就想直接不行,那咱们来间接的. 这就是我们今天主要要讲的: ...

  7. 基于Spring Boot的线程池监控方案

    前言 这篇是推动大家异步编程的思想的线程池的准备篇,要做好监控,让大家使用无后顾之忧,敬畏生产. 为什么需要对线程池进行监控 Java线程池作为最常使用到的并发工具,相信大家都不陌生,但是你真的确定使 ...

  8. tensorflow源码解析之common_runtime拾遗

    把common_runtime中剩余的内容,按照文件名排序进行了简单的解析,时间原因写的很仓促,算是占个坑,后续有了新的理解再来补充. allocator_retry 有时候内存分配不可能一次完成,为 ...

  9. 如何实现ARC中weak功能?

    原文链接 我们都知道ARC中weak与assign或者说unsafe_unretained最大的不同就是设置weak属性后,系统会在对象被释放后自动将指向对象的指针置为nil,而assign则会产生一 ...

  10. 如何修改windows Server 2012 远程桌面连接默认端口

    如何修改windows Server 2012 远程桌面连接默认端口   修改windows 2012/win8.win7远程桌面连接默认端口一般需要修改注册表四个地方[HKEY_LOCAL_MACH ...