LeetCode-中等-29. 两数相除
LeetCode-中等-29. 两数相除
题目
引用自:LeetCode-中等-29. 两数相除(如有侵权联系删除)
给定两个整数,被除数 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
提示:
- 被除数和除数均为 32 位有符号整数。
- 除数不为 0。
- 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。
解题:
没什么好说的,是不可能的!这个题还是挺考察一部分对基本知识的掌握的。
根据题目要求,此题意思让我们手动模拟计算机除法。所以我们首先要了解结计算机世界中如何进行除法运算。
其实整体逻辑与我们平时手动计算很相似,只不过对于计算机而言,都是二进制数。
例如手动算18
除以7
的时候:
从被除数18
的最高位(左边)开始:
- 1.第一位 是
1
,用1
除以7
不够,只能商0
,余下1
因为1 - 7 * 0 = 1
- 2.第二位 是
8
,用18
(1 * 10 + 8 = 18
, 用上一位除完的余数乘以10
,再加上本位的数)除以7
,商2
,余下4
。 - 计算完被除数的最后一位之后,把我们每位算得的商合在一起。第一位是
0
,第二位是2
,所以就是0 * 10 + 2 = 2
。
所以最后结果为 商:2
余:4
。
可能有人就会想,在第二步计算商2
的时候,不是要心算一下商1
余下11
,商2
余4
,这个判断过程不是要计算2 * 7
吗,这用到乘法就不符合题目要求了。但是我们仔细想一下,其实我们不需要用到乘法,因为在二进制情况下,其实要么就是商0
,意味着需要除的那个数小于除数,要么就商1
,意味着需要除的那个数大于等于除数,而不可能商2
,并且二进制里面根本也不会出现2
,如下面的二进制计算过程。
对于二进制的话:
18
对应的二进制数为10010
7
对应的二进制数为111
从被除数10010
的最高位(左边)开始:
- 1.第1位 是
1
,用1
除以111
不够,商0
,所以1 - 111 * 0 = 1
,余下1
。 - 2.第2位 是
0
,余数1 * 2 + 0 = 10
,用10
除以111
不够,商0
,所以10 - 111 * 0 = 10
,余下10
。 - 3.第3位 是
0
,余数10 * 2 + 0 = 100
,用100
除以111
不够,商0
,所以100-111*0 = 100
,余下100
。 - 4.第4位 是
1
,余数100 * 2 + 1 = 1001
,用1001
除以111
够,商1
,所以1001-111*1=10
,余下10
。 - 5.第5位 是
0
,余数10*2 + 0 = 100
,用100
除以111
不够,商0
,所以100-111*0=100
,余下100
。 - 6.计算到最后,余数位
100
,转为十进制就是4
,而商只需将每次计算的商合起来,我们5次计算的结果分别是'0'、'0'、'0'、'1'、'0'
,所以合起来的时候需要计算((((((0 * 2) + 0) * 2) + 0) * 2 + 1) * 2) + 0 = 00010 = 10
,我们又需要用到乘法了,怎么办呢。我们知道,在计算机中,本身数的存储方式就是以二进制的形式存储的,所以当我们想要把某个数乘2
的时候,只需要将这个数进行一次左移的位运算即可,如:十进制3乘以2结果为6,而十进制3在计算机中的存储形式为 11 (这里暂不考虑32为系统或64位系统),那么我们把 11 左移一位为 110,转为十进制也同样是 6,其实对于十进制数也是如此,如果我们想把十进制3乘以10, 那我们是不是也可以直接把 3 左移一位等到 3_,然后空位补上0,就得到30
。这样也就解决了合并商的需要用到乘法的问题。
到这里基本上就大概清楚如何不用乘除法和mod运算来进行整数除法了,接下来只需要注意处理一下正负号,和整数的大小限制即可通过LeetCode。
除此之外,需要了解一下python中的bin()
函数,可以把十进制数转为二进制数的字符串形式,可能需要用到。
代码:
# 截断小数位class Solution:def divide(self, dividend: int, divisor: int) -> int:# 判断除数和被除数的正负号 并确定结果的正负号is_pos_1 = True if dividend > 0 else Falseis_pos_2 = True if divisor > 0 else Falseresult_is_neg = True if is_pos_1 ^ is_pos_2 else False# 将两个值都转换为正数,其中把被除数转换为二进制字符串'0bXXX',并去掉'0b'和负号dividend_2_pos = bin(dividend).replace('0b', '').replace('-', '')divisor_pos = -divisor if divisor < 0 else divisor# 按两个正数计算除法temp_divided = 0result = 0for number in dividend_2_pos:temp_divided = (temp_divided << 1) + int(number, 2)if temp_divided >= divisor_pos:temp_divided -= divisor_posresult = (result << 1) + 1else:result = (result << 1)# 判断正负号,以及确定数值范围在[−2^31, 2^31 − 1]result = -result if result_is_neg else resultresult = -2147483648 if result < -2147483648 else resultresult = 2147483647 if result > 2147483647 else resultreturn result
除此之外,这个题目要求的是让截断小数位,但是以下是一个四舍五入的版本的。
# 小数位四舍五入class Solution1:def divide(self, dividend: int, divisor: int) -> int:# 判断除数和被除数的正负号 并确定结果的正负号is_pos_1 = True if dividend > 0 else Falseis_pos_2 = True if divisor > 0 else Falseresult_is_neg = True if is_pos_1 ^ is_pos_2 else False# 将两个值都转换为正数,其中把被除数转换为二进制'0bXXX',并去掉'0b'和负号dividend_2_pos = bin(dividend).replace('0b', '').replace('-', '')divisor_pos = -divisor if divisor < 0 else divisor# 按两个正数计算除法temp_divided = 0result = 0for number in dividend_2_pos:temp_divided = (temp_divided << 1) + int(number, 2)if temp_divided >= divisor_pos:temp_divided -= divisor_posresult = (result << 1) + 1else:result = (result << 1)# 我们可以发现, 在进行reslut 正负号判断之间进行向上或者向下取整可以 统一起来,否则需要分result的正负号分别讨论向上向下取整# 判断是否向上取整 <我们可以把最后的余数乘以2, 然后与除数比较大小,# 如果大于除数,说明余数是大于除数的1/2, 那么最后就应该向上取整,否则向下取整>is_rounding_up = True if temp_divided << 1 >= divisor_pos else False# 我们这里算到被除数的最后一位就停止了,所以result 本身就是一个整数# 所以,若向上取整,那么reslut需要 +1,否则保持不变result = result + 1 if is_rounding_up else result# 判断正负号,以及确定数值范围在[−2^31, 2^31 − 1]result = -result if result_is_neg else resultresult = -2147483648 if result < -2147483648 else resultresult = 2147483647 if result > 2147483647 else resultreturn result
测试:
class Solution:def divide(self, dividend: int, divisor: int) -> int:# 判断除数和被除数的正负号 并确定结果的正负号is_pos_1 = True if dividend > 0 else Falseis_pos_2 = True if divisor > 0 else Falseresult_is_neg = True if is_pos_1 ^ is_pos_2 else False# 将两个值都转换为正数,其中把被除数转换为二进制字符串'0bXXX',并去掉'0b'和负号dividend_2_pos = bin(dividend).replace('0b', '').replace('-', '')divisor_pos = -divisor if divisor < 0 else divisor# 按两个正数计算除法temp_divided = 0result = 0for number in dividend_2_pos:temp_divided = (temp_divided << 1) + int(number, 2)if temp_divided >= divisor_pos:temp_divided -= divisor_posresult = (result << 1) + 1else:result = (result << 1)# 判断正负号,以及确定数值范围在[−2^31, 2^31 − 1]result = -result if result_is_neg else resultresult = -2147483648 if result < -2147483648 else resultresult = 2147483647 if result > 2147483647 else resultreturn resultclass Solution1:def divide(self, dividend: int, divisor: int) -> int:# 判断除数和被除数的正负号 并确定结果的正负号is_pos_1 = True if dividend > 0 else Falseis_pos_2 = True if divisor > 0 else Falseresult_is_neg = True if is_pos_1 ^ is_pos_2 else False# 将两个值都转换为正数,其中把被除数转换为二进制'0bXXX',并去掉'0b'和负号dividend_2_pos = bin(dividend).replace('0b', '').replace('-', '')divisor_pos = -divisor if divisor < 0 else divisor# 按两个正数计算除法temp_divided = 0result = 0for number in dividend_2_pos:temp_divided = (temp_divided << 1) + int(number, 2)if temp_divided >= divisor_pos:temp_divided -= divisor_posresult = (result << 1) + 1else:result = (result << 1)# 我们可以发现, 在进行reslut 正负号判断之间进行向上或者向下取整可以 统一起来,否则需要分result的正负号分别讨论向上向下取整# 判断是否向上取整 <我们可以把最后的余数乘以2, 然后与除数比较大小,# 如果大于除数,说明余数是大于除数的1/2, 那么最后就应该向上取整,否则向下取整>is_rounding_up = True if temp_divided << 1 >= divisor_pos else False# 我们这里算到被除数的最后一位就停止了,所以result 本身就是一个整数# 所以,若向上取整,那么reslut需要 +1,否则保持不变result = result + 1 if is_rounding_up else result# 判断正负号,以及确定数值范围在[−2^31, 2^31 − 1]result = -result if result_is_neg else resultresult = -2147483648 if result < -2147483648 else resultresult = 2147483647 if result > 2147483647 else resultreturn resultif __name__ == "__main__":so = Solution()so1 = Solution1()dividend = 11divisor = 4print('测试1: \ndividend = 11 divisor = 4')print('小数位截断:dividend / divisor = ', so.divide(dividend, divisor))print('四舍五入:dividend / divisor = ', so1.divide(dividend, divisor))print()dividend = 12divisor = 5print('测试2: \ndividend = 12 divisor = 5')print('小数位截断:dividend / divisor = ', so.divide(dividend, divisor))print('四舍五入:dividend / divisor = ', so1.divide(dividend, divisor))
总结:
很不错的一道题嘛,因为这个题还专门回顾了一下计算机的一些位运算,和怎么算减法(你还记得减法怎么算的吗,hia hia hia),温故而知新~!
并且又重新了解一下bin()、int(number, 2)
这两个好玩的函数!
LeetCode-中等-29. 两数相除相关推荐
- leetcode 29.两数相除
leetcode 29.两数相除 题目描述 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 ...
- LeetCode高频题29. 两数相除:不用加减乘除号,求加法,减法,乘法,除法
LeetCode高频题29. 两数相除 提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目 互联网大厂们在公司养了一大批ACM竞赛 ...
- Java实现 LeetCode 29 两数相除
29. 两数相除 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商 ...
- leetcode 29 两数相除 C语言
题目 leetcode 29 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 diviso ...
- LeetCode 29. 两数相除(位运算)
1. 题目 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示 ...
- leetcode —— 29. 两数相除
给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 整数除法的结果 ...
- LeetCode 27移除元素28实现strStr()29两数相除
维护幸苦,如有打卡欢迎关注公众号bigsai回复进群,如有帮助欢迎点赞支持! 移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长 ...
- [LeetCode]29 两数相除和一个小坑点
给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符.返回被除数 dividend 除以除数 divisor 得到的商.示例 1:输入: ...
- leetcode 29.两数相除(python3)68ms
题目描述: 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 整 ...
最新文章
- IOS开发笔记17-Object-C中的继承
- hdu1042 java_N! hdu1042 | 学步园
- SpringBoot简单使用ehcache
- 京东自动评论脚本_京东时光机python脚本 自动完成任务
- java二叉树代码_JAVA语言实现二叉树生成的代码教程
- Opencv基础画图函数——line、circle、rectangle、Rect、ellipse、polylines、putText函数的用法
- 看故事学知识,这篇Java代理的文章妙啊!
- 互联网为什么要版权,我支持资源共享。
- 【TSP】基于matlab hopfield神经网络求解旅行商问题【含Matlab源码 408期】
- 2022年第十二届MathorCup移动通信网络站址规划和区域聚类问题
- A40i使用笔记:使用QT调用aplay播放wav音频/混音
- Nginx 负载均衡演示之 upstream 参数、 location 参数等示例说明
- 期货十三篇 第九篇 心态篇
- 关于Eureka注册中心启动报错的原因
- IntelliJ IDEA:安装/搭建/配置/插件
- Linux赋予用户读写权限
- 大气简洁手绘风商务计划书PPT模板
- 发生系统错误 1219。不允许一个用户使用一个以上用户名与服务器或共享资源的多重连接。
- excel服务器客户端在哪个文件夹,excel服务器客户端安装配置
- SecurityManager——Java 语言的保护伞