算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 两数相除,我们先来看题面:

https://leetcode-cn.com/problems/divide-two-integers/

给定两个整数,被除数和除数,要求在不使用除法的情况下计算出两数的商

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

Return the quotient after dividing dividend by divisor.

The integer division should truncate toward zero.

样例 1:

Input: dividend = 10, divisor = 3
Output: 3

样例 2:

Input: dividend = 7, divisor = -3
Output: -2

注意:

  • 除数和被除数都在32位int的范围内

  • 除数不为0

  • 对于超界的情况返回
  • Both dividend and divisor will be 32-bit signed integers.
  • The divisor will never be 0.
  • Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−,   − 1]. For the purpose of this problem, assume that your function returns  − 1 when the division result overflows.

题解

老规矩,我们依然从最简单的情况开始入手。我们都知道,在计算机内部,是二进制的,而二进制是只能进行加减的。所以所有的乘法和除法的操作其实最终都会转换为加减法来进行。对于这道题而言也是一样的,既然禁止我们使用除法,那么我们可以用减法来代替。

暴力

最简单的策略就是我们可以用一个循环去不停地减,然后用一个累加器计算到底执行了多少次减法,当不够减的时候则停止。整个流程非常简单,但是我们还需要考虑一下正负号的问题,按照排列组合来看,被除数和除数一共有4中正负号的情况。但我们并不需要考虑那么多,这四种情况可以简单地归并成是否同号两种,然后进一步分析又会发现是否同号的计算过程并没有差别,唯一会影响的只有最后结果的正负号。还有一点比较令人在意的是提示当中说的可能会超界的情况,我们来分析一下,其实会超界的可能性只有一个。那就是除以-1的情况,会得到,而32位int的正数范围最大是,所以我们需要在意这个问题。不过好在对于Python而言,int是没有范围的,所以可以忽略这个问题,只需要最后特判一下结果,但是对于C++和Java等语言而言,需要特殊处理,比如可以使用long long或者是全部转成负数。我们来总结一下上面的过程,我们可以先将除数和被除数全部转化为正数,然后用一个标记flag来记录它们是否同号。再计算完结果之后,需要判断一下结果的范围是否越界,如果越界返回。代码如下:

class Solution:def divide(self, dividend: int, divisor: int) -> int:# 判断是否同号        flag = (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0)        ret = 0# 全部赋值为正        dividend, divisor = abs(dividend), abs(divisor)        start = 0# 模拟除法while start + divisor <= dividend:            start += divisor            ret += 1# 防止越界,注意只有正数才有可能越界return min(ret, (1 << 31) - 1) if flag else -ret

这个代码当然是没有问题的,但是如果你真的这么提交,那么一定会超时。原因也很简单,当除数非常小,比如是1的时候,那么我们的循环次数就是被除数的大小。当我们给定一个很大的被除数的时候,会超时就是显然的了。

二进制优化

接下来讲的这个算法很重要,是快速幂等许多算法的基础,由于本题当中不是进行的幂运算,所以不能称作是快速幂算法,一时间也没有什么好的名字,由于本质上是通过二进制的运算来优化,所以就称为二进制优化吧。在讲解算法之前,我们先来分析一下bad case出现的原因。之所以会超时,是因为有可能被除数非常小,比如是1,这个时候我们一位一位地减就非常耗时。那么很自然地可以想到,我们可不可以每次不是减去一个1,而是若干个1,最后把这些减去的数量加起来,是不是会比每次减去一个要更快一些呢?但是还有细节我们不清楚,我们怎么来确定这个每次应该减去的数量呢?如果确定了之后发现不够减,又应该怎么办呢?要回答上面这个问题,需要对二进制有比较深入的理解。我们先把刚才的问题放一放,来看一看二进制对于除法的解释。举个简单的例子,比如15 / 3 = 5。我们知道15等于5个3相乘,那么我们把它们都写成二进制。15的二进制是1111,3的二进制是0011,5的二进制是0101,我们重点来看这个5的二进制。5的二进制写成0101,展开的话会得到是,也就是说我们可以把15看成,这个式子写成是。也就是说我们可以把被除数看成是若干个2的幂乘上除数的和,这就把一个除法问题转化成了加法问题。同样我们把求解商转化成了求解商的二进制表达,二进制表达有了,最后的商无非是再进行一个求和累加即可。最后,我们来分析一下,为什么能够优化。因为题目当中已经限定了,除数和被除数都在32位的int范围。也就是说最多只有32个二进制位,那么我们的循环次数最多也就是32次。通过二进制优化,我们把原本一个的问题,降级成了,这两者之间差了不止一个数量级,当然要快得多。我们把上面这个思路写成代码,就可以得到答案:

class Solution:def divide(self, dividend: int, divisor: int) -> int:# 前面处理和之前一样        flag = (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0)        ret = 0        dividend, divisor = abs(dividend), abs(divisor)# 预处理二进制数组        binary = [0 for _ in range(33)]# 第0位即2的零次方乘上除数,所以就是除数本身        binary[0] = divisorfor i in range(1, 33):# 后面每一位是前面一位的两倍,因为二进制# << 是位运算左移操作,等价于*2,但是速度更快            binary[i] = binary[i-1] << 1for i in range(32, -1, -1):if binary[i] <= dividend:                dividend -= binary[i]# 答案加上2^i                ret += (1 << i)return min(ret, (1 << 31) - 1) if flag else -ret

这段代码不长,也没有用到什么特别牛哄哄的算法,无非是对二进制的一些运用。但是对于对二进制不够熟悉的初学者而言,想完全搞明白可能有些费劲,这也是很正常的。希望大家能够沉下心来好好理解,如果实在看不懂也没关系,在以后快速幂等算法当中,还会和它见面的。今天的文章就是这些,如果觉得有所收获,请顺手点个在看或者转发吧,你们的举手之劳对我来说很重要。

上期推文:

LeetCode1-20题汇总,速度收藏!LeetCode刷题实战21:合并两个有序链表LeetCode刷题实战23:合并K个升序链表LeetCode刷题实战24:两两交换链表中的节点LeetCode刷题实战25:K 个一组翻转链表

postgre非零相除等于0_LeetCode刷题实战29:两数相除相关推荐

  1. c语言两数相除等于小数多少,c语言程序两数相除精确到小数点后k位

    题目: 输入两个整数m和n,及另一正整数k,计算m/n,结果精确到小数点后k位 1.问题分析与方案设计. 1.首先解决输入问题.题目要求输入三个整数m,n,k.所以定义input()函数,使输入的为正 ...

  2. leetcode 29.两数相除

    leetcode 29.两数相除 题目描述 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 ...

  3. 【leedcode刷题1】两数之和

    [leedcode刷题 1]两数之和 大家好,小生不才,从今天开始将自己刷题的过程记录在博客中,因为能力有限,所以如果有什么错的地方希望大家积极指正,不胜感激. 题目 给定一个整数数组 nums 和一 ...

  4. LeetCode高频题29. 两数相除:不用加减乘除号,求加法,减法,乘法,除法

    LeetCode高频题29. 两数相除 提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目 互联网大厂们在公司养了一大批ACM竞赛 ...

  5. LeetCode-中等-29. 两数相除

    LeetCode-中等-29. 两数相除 题目 引用自:LeetCode-中等-29. 两数相除(如有侵权联系删除) 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不 ...

  6. Java实现 LeetCode 29 两数相除

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

  7. leetcode第29题python版两数相除

    class Solution:"""29. 两数相除给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符.& ...

  8. LeetCode 27移除元素28实现strStr()29两数相除

    维护幸苦,如有打卡欢迎关注公众号bigsai回复进群,如有帮助欢迎点赞支持! 移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长 ...

  9. leetcode —— 29. 两数相除

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

最新文章

  1. ping 命令还能这么玩?
  2. 后端:Java 中 10 大坑爹功能!
  3. [Jobdu] 题目1530:最长不重复子串
  4. vsftp服务器搭建
  5. 直设计map.html页面,map4.html
  6. python oop 实践_Python OOP示例?
  7. C# log4net App.config 配置系统未能初始化问题
  8. 【Linux】【操作】Linux操作集锦系列之一——定时任务
  9. 用python进行数据分析(二:数据处理)
  10. 许竹青、骆艾荣:数字城市的理念演化、主要类别及未来趋势研究
  11. exe制作成安装包,Inno Setup软件使用教程
  12. Failing OffsetCommit request since the consumer is not part of an active group
  13. blender 制作城市建筑模型
  14. 免费网站翻译整个文档并保留原格式
  15. 又一大佬加盟OpenAI!他还是姚班学霸陈立杰的导师
  16. 阿里主流开源框架大汇总
  17. 搭建ngrok服务器
  18. Netlify前端自动化部署服务
  19. python合并pdf_python如何将多个PDF进行合并
  20. html5公司年终抽奖程序源码按数字随机抽奖

热门文章

  1. 090925 H 广联达之道 培训笔记
  2. WSL1安装GUI界面
  3. C语言之避免编译警告:unused用法(七)
  4. git diff生成patch用法
  5. Mac触发角锁屏不睡眠
  6. linux软连接目标不存在,Linux ln创建软连接之后无法使用,无法whereis
  7. 树莓派 cuda加速_用树莓派4b构建深度学习应用(四)PyTorch篇
  8. 研究生不知道怎么看论文?赶紧把学长的经验码起来
  9. mysql存储php数组_mysql数据库存储PHP数组、对象的方法
  10. lintOnSave设置