LCR 001 两数相除

一.题目:
. - 力扣(LeetCode)
二.原始解法-超时:
class Solution:
def divide(self, a: int, b: int) -> int:

1)分析:

除法计算,不能使用除法符号,可以理解为实现除法

除法原理是减法次数,a/b可以理解为a-b重复多次至结果小于0,假设此时余数为c

由于注意事项第一点已说明直接截取余数部分保留整数,返回重复次数即可,如果a,b正负不同,返回负数,否则返回正数

如果返回结果不在[−231, 231−1]范围,则返回231 − 1

2)判断输入有效性

if b == 0:
return

这里有一个易忘记知识点:python内置函数-幂计算x的n次方为x ** n

if a < -2 ** 31 or a > 2 ** 31 - 1 or b < -2 ** 31 or b > 2 ** 31 - 1:
return
if a == 0:
return 0

3)判断返回符号:

if a > 0 and b < 0 or a < 0 and b > 0:
symbol = -1
else:
symbol = 1

4) 使用while循环计算,按绝对值计算除法

这里有一个易忘知识点:python内置函数-绝对值为abs(-x)=x

current_a = abs(a)
abs_b = abs(b)
result = 0
while current_a - abs_b >= 0:
current_a = current_a - abs_b # 被除数刷新为差
result += 1

5)赋值符号

result = -result if symbol == -1 else result

6)判断结果溢出

if result < -2 ** 31 or result > 2 ** 31 - 1:
return 2 ** 31 - 1
else:
return result
三.正确解法及好的讲解、力扣解法参考:
好的讲解:《剑指 Offer》专项突破版 - 面试题 1 : 整数除法_输入2个int型整数,它们进行除法计算并返回商-CSDN博客
Python实现易于理解版本: . - 力扣(LeetCode)

四.对这个标准解法自己的消化分析:
首先被除数和除数的边界在 [−2 31 , 2 31 −1]范围中,题目描述中提到溢出情况,就是指商的数值超出了这个范围,那么什么情况下商会超出这个范围呢?可以把这个范围画到数轴上看一下,如下图:

上面这个图红色箭头表示超出范围的数值部分,推出了两种可能的不等式组,即
当商x<=0时,|x|>-a 或者 当商x>=0时,|x|>b。这两个不等式如果至少要成立一个,就得满足|x|大于-a和b的最小值,如果连这个条件都不满足,那么这个不等式组是不成立的。即|x|>min( 2 31 , 2 31 −1 ),也就是|x|> 2 31 −1,那么为什么要用|x|而不是直接用x判断呢,因为除法的符号是根据除数和被除数是否符号一致判断的,为了使分析简单,可以先忽略符号。那么知道了溢出时候商x的最小值,看下当被除数和除数满足这个范围 [−2 31 , 2 31 −1] 时,是否会出现一个商处于这个溢出范围,也就是商的绝对值比 2 31 −1大,即|x|> 2 31 −1;
因为这是整数除法,所以商的绝对值一定小于被除数,又得到一个不等式:|a|/|b|=x且a、b皆为整数则|x|<|a|,再结合上面的结论,可以推出|x|的取值范围: 2 31 −1 < |x|<|a|,那么是否存在这种情况呢?只要判断是否存在 2 31 −1< |a|,有的,当|a|= 2 31 时,此时如果|b|=1,那么|x| = 2 31 了。
那么就是a = 2 31 时,b=1或-1;或a=- 2 31 时,b=1或-1,但是因为a的范围在 [−2 31 , 2 31 −1]之间,所以只有一种可能, a=- 2 31 ,b=-1结果是此时商会溢出,需要特殊处理。那么就在初始化的时候拦截这种输入,直接处理特殊场景即可,边界问题分析完了,现在看非特殊场景下求商绝对值的算法(刚才说了,商的符号先放到一边不考虑)
上面我的原始解法是最直观的根据除法的原理是减法来计算的,但是超时了,因为极端情况下当被除数为 2 31 −1,除数为1时,需要减 2 31 −1次,计算次数太多了。那么有没有简单办法呢?可以考虑刚才说的这种极端情况,如果每次减的不是除数,而是除数的N倍,然后商再加上这个N倍,就相当于减少了计算次数,其实就是利用除数膨胀N倍的时候,商会缩小N倍,这个N最好是2的n次方,这样计算次数就更少了。也就是说,用a和b的 2 31 倍数比较,如果a比这个小,就减少倍数为2的30次,这样一直减少到a比b扩大2的某次方要大,说明a-b一定大于2的某次方,那么a除以b的2的某次方的商一定大于1,也就是a除以b一定大于商乘以2的某次放,举个例子:17/1=17,如果用原始减法算,需要计算17次,如果用17-1*2的4次方,发现此时差大于0,那么17/1的商一定大于2的4次方,因为17就是比1大那么多倍,即商=16,然后计算17-1*2的4次方=1,此时差=除数,商再加1直到差<除数。即上面力扣解法中的这部分核心代码:

temp是2的n次方的n,从31次方开始倒推,只要a比b*2的n次方大,a就减去当前被扩大了的除数(其实还是用了除法的原理是减法,只是除数膨胀了),quo是商,当除数膨胀了的时候,商也要膨胀,因为计算次数被减少了,膨胀的数值就是b扩大的倍数
同时这道题扩大n倍由于题目要求不能使用乘法,只能使用位移,Python中的左移<<就是扩大2的n次方,又因为要判断a,b的输入值处理溢出,需要了解python中2的n次方运算符是**
五.实现如下:
class Solution:
def divide(self, a: int, b: int) -> int:

处理a,b是否在题目范围,及除数是否为0非法,退出计算

if a < -2**31 or a > 2**31 +1 or b < -2**31 or b > 2**31 +1 or b == 0:
return

处理会导致商溢出的情况 a=-2**31,b=1或-1,直接按题目要求返回溢出默认值

if a == -2**31 and b == -1:
return 2**31 - 1

处理被除数为0,直接返回0

if a == 0:
return 0

处理非特殊情况,先简化除法为绝对值,flag为商的符号,然后a,b取绝对值

flag = True if (a > 0 and b > 0) or (a < 0 and b <0) else False
a,b = abs(a),abs(b)

temp为2的n次幂的n,即除数左移位数,初始化为题目最大值31,quo为商,当temp为最大值时,商初始化为最小值0

temp,quo = 31,0

开始用除法原理减法+除数倍数膨胀计算

while temp >= 0:
if a >= b << temp:#此时可以处理商和被除数了
a -= b << temp
quo += 1 << temp
temp -= 1

计算完成,给商赋符号

if not flag:
quo = -quo
return quo

相关推荐
草履虫建模20 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq1 天前
分布式系统安全通信
开发语言·c++·算法
Jasmine_llq1 天前
《P3157 [CQOI2011] 动态逆序对》
算法·cdq 分治·动态问题静态化+双向偏序统计·树状数组(高效统计元素大小关系·排序算法(预处理偏序和时间戳)·前缀和(合并单个贡献为总逆序对·动态问题静态化
学嵌入式的小杨同学1 天前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
Re.不晚1 天前
Java入门17——异常
java·开发语言
爱吃rabbit的mq1 天前
第09章:随机森林:集成学习的威力
算法·随机森林·集成学习
精彩极了吧1 天前
C语言基本语法-自定义类型:结构体&联合体&枚举
c语言·开发语言·枚举·结构体·内存对齐·位段·联合
好家伙VCC1 天前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
(❁´◡`❁)Jimmy(❁´◡`❁)1 天前
Exgcd 学习笔记
笔记·学习·算法
YYuCChi1 天前
代码随想录算法训练营第三十七天 | 52.携带研究材料(卡码网)、518.零钱兑换||、377.组合总和IV、57.爬楼梯(卡码网)
算法·动态规划