LeetCode 29: 两数相除(DivideTwoIntegers)

难度:medium
本题同时也是《剑指offer 专项突击》的第一题。

Problem

https://leetcode.cn/problems/divide-two-integers/
以及
https://leetcode.cn/problems/xoh6Oh/

给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 ‘*’、除号 ‘/’ 以及求余符号 ‘%’ 。

注意:

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335)
= -2 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231−1]。本题中,如果除法结果溢出,则返回 231 − 1

示例 1:

输入:a = 15, b = 2 输出:7 解释:15/2 = truncate(7.5) = 7
示例 2:

输入:a = 7, b = -3 输出:-2 解释:7/-3 = truncate(-2.33333…) = -2
示例 3:

输入:a = 0, b = 1 输出:0
示例 4:

输入:a = 1, b = 1 输出:1

提示:

-231 <= a, b <= 231 - 1 b != 0

没有灵魂的解法

最直观的想法 是将除法转为暴力减法, 直到减到 小于除数为止。复杂度是 O ( n ) \mathcal{O}(n) O(n),当除数很小,比如为1时,效率太低。

		a=abs(a)
		b=abs(b)
		res = 0
		while a>=b:
		    a-=b
		    res+=1

优化后的解法

先说有哪些坑:

  1. 溢出问题。(也看到有C/C++解法是将 int 转为 long)注意到如果全部转为正数做,会面临 − 2 31 -2^{31} 231=> 转为 2 31 2^{31} 231溢出的情况。

示例5:
a=-2147483648
b=-1

所以应该先把除数和被除数都转为负数,运算后再考虑符号问题。但是只有一种情况会溢出,也就是输入为 ( − 2 31 ) / ( − 1 ) = 2 31 (-2^{31})/(-1)=2^{31} (231)/(1)=231时会溢出。这种case写个if排除就行了。

        INT_MIN, INT_MAX = -2**31, 2**31 - 1
        assert b!=0
        if a==INT_MIN and b==-1:
            return INT_MAX

对于其他case的符号判断, 由于不允许使用符号*, /, %。可以通过最高位判断符号,一个异或搞定。

        if (a ^ b) <0:
            sign=-1
        else:
            sign =1
  1. 计算复杂度的问题。有不少解法(包括《剑指offer 专项》书上的解法)都是优化为考虑 减去除数的倍数,这种解法在python下可能还是超出时间(自己测试不会), 复杂度是 O ( l o g n    l o g n ) O(log n \ \ log n ) O(logn  logn)
    思路大概是这样的:
    在这里插入图片描述

在这里插入图片描述

完整代码(思路:减去除数2^k倍)

class Solution:
    def divide(self, a: int, b: int) -> int:
        INT_MIN, INT_MAX = -2**31, 2**31 - 1
        assert b!=0
        if a==INT_MIN and b==-1:
            return INT_MAX

        if (a ^ b) <0:
            sign=-1
        else:
            sign =1


        a=abs(a)
        b=abs(b)
        K=0
        while a>=b:
            value, k = b,1
            while a-value-value>=b:
                value+=value
                k+=k
            a-=value
            K+=k

        if sign==-1:
            K = -K
        return K
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值