题目描述

给定两个整数,被除数 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. 通过ILSpy反编译工具和ilasm修改.NET程序

    文章来源:https://blog.peos.cn/2016/12/26/ilspy-ilasm-ildasm-net.html 金庸群侠传X中,田青文.木婉清.王语嫣的点穴游戏忒难过了,所以上网摸索 ...

  2. [iptables] 基于iptables实现的跨网络通信

    描述 在很多业务场景下,会遇上很多诡异的需求,不仅限于文章提及的需求,还有各种五花八门的需求,大部份的这些需求的产生都是来源于以前设计.规划上导致的问题.所以我们都会想尽办法为客户解决问题,维护好客户 ...

  3. Oracle子查询临时表

    ORACLE 临时表,可以有两种类型的临时表:会话级临时表.事务级临时表. 会话级临时表: 因为这个临时表中的数据和你的当前会话有关系,当你当前 SESSION 不退出的情况下,临时表中的数据就还存在 ...

  4. vmware扩容centos根目录

    在vmware中编辑,给磁盘扩容 在centos中使用命令fdisk /dev/sda 输入n创建新分区 输入p创建主分区 回车,默认分区号 回车,默认起始扇区 回车,默认last扇区 输入t,改变分 ...

  5. journactl日志查看命令-渐入佳境

    --作者:飞翔的小胖猪 --创建时间:2021年2月27日 内容 journalctl是systemd统一管理所有unit(服务)的启动日志.可以通过journalctl一个命令查看所有日志. 所有用 ...

  6. MyEclipse 启动tomcat本地服务,debug模式,代码一直不同步

    今天写代码遇到一个问题,上午还能正常运行的代码,在eclipse中显示正常,但在游览器中就出现了差异,在网上找了很多方法: 1.add and remove项目,清理tomcat部署目录下的项目,清理 ...

  7. 携程applo配置

    1.官网文档 https://github.com/ctripcorp/apollo/wiki/%E5%88%86%E5%B8%83%E5%BC%8F%E9%83%A8%E7%BD%B2%E6%8C% ...

  8. Python第三讲

    今日内容概要 数据类型及内置方法 字符编码 文件处理 函数简介 今日内容详细 数据类型及内置方法 列表 name_list =['jason','oscar','tony','kevin'] 1.索引 ...

  9. 『现学现忘』Docker相关概念 — 3、IaaS、SaaS、PaaS服务模式补充

    目录 1.IaaS服务模式 2.PaaS服务模式 (1)何时使用PaaS (2)PaaS的特点 (3)PaaS优势 3.SaaS服务模式 云计算通俗来说就是输入/输出和计算不在一个主机上.计算要用到计 ...

  10. 树莓派4B安装 百度飞桨paddlelite 做视频检测 (一、环境安装)

    前言: 当前准备重新在树莓派4B8G 上面搭载训练模型进行识别检测,训练采用了百度飞桨的PaddleX再也不用为训练部署环境各种报错发愁了,推荐大家使用. 关于在树莓派4B上面paddlelite的文 ...