当前位置: 首页 > news >正文

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
http://www.lryc.cn/news/488956.html

相关文章:

  • 数据库、数据仓库、数据湖、数据中台、湖仓一体的概念和区别
  • vue 的生命周期函数
  • 单片机UART协议相关知识
  • 【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
  • OpenCV笔记:图像去噪对比
  • A-B数对(二分查找)
  • Vue 的各个生命周期
  • 实现简易计算器 网格布局 QT环境 纯代码C++实现
  • 后端开发详细学习框架与路线
  • 2.langchain中的prompt模板 (FewShotPromptTemplate)
  • FairGuard游戏加固实机演示
  • Spark使用过程中的 15 个常见问题、详细解决方案
  • 算法【最长递增子序列问题与扩展】
  • k8s篇之flannel网络模型详解
  • windows 和 linux检查操作系统基本信息
  • Oracle OCP认证考试考点详解082系列22
  • 线性回归 - 最小二乘法
  • Linux - 线程基础
  • 网络爬虫——分布式爬虫架构
  • RT_Thread内核源码分析(三)——线程
  • 正排索引和倒排索引
  • 丹摩 | 重返丹摩(上)
  • Frontend - 防止多次请求,避免重复请求
  • RHCE的学习(22)
  • 【前端知识】简单讲讲什么是微前端
  • AWS IAM
  • 丹摩|丹摩助力selenium实现大麦网抢票
  • 基于Qt/C++/Opencv实现的一个视频中二维码解析软件
  • 智慧理财项目测试文档
  • R | 统一栅格数据的坐标系、分辨率和行列号