Leetcode 029 两数相除 思路详解+反思易错 Python实现

先来点废话。觉得自己写的博客质量太低了,一是代码健壮度很多地方还有待优化,其次是有些题的整体思路不够宽阔(没有做到一题多解)。做题总是追求AC, AC完了后就不管了。所以在从现在反省一下,要保证每道题的质量,详细讲解我搜索到的所有解法。

本人一直在努力地积累Leetcode上用Python实现的题,并且会尽力讲清每道题的原理,绝不像其他某些博客简略地带过。
如果觉得讲的清楚,欢迎关注。

题目:

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

返回被除数 dividend 除以除数 divisor 得到的商。

示例 1:

输入: dividend = 10, divisor = 3
输出: 3

示例 2:

输入: dividend = 7, divisor = -3
输出: -2

说明:

  • 被除数和除数均为 32 位有符号整数。
  • 除数不为 0。
  • 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231,  231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。



思路:这道题一开始我用加减的方式去模拟乘除做的,结果很容易TLE。所以这道题我们要去想如何加快我们的加和速度。

网上的其他很多解大概都是用位运算符的。

总结一下这道题思路:1.通过位运算模拟*2,加快扩大divisor的速度

2.通过整除或者其他方式。

位运算最快,整除等属于第二梯队。

先来看位运算解法:

class Solution:
def divide(self, dividend, divisor):
"""
:type dividend: int
:type divisor: int
:rtype: int
"""
#首先这一句就很python,postive 为true是符号相同
positive = (dividend < 0) is (divisor < 0)
dividend, divisor = abs(dividend), abs(divisor)
res = 0
#检查dividend是否大于divisor
#如果还小于则进行小精度的逼近dividend
while dividend >= divisor:
temp, i = divisor, 1
#增大逼近dividend的步伐
#i不断增加, temp不断减少
while dividend >= temp:
#经过上一句的判断,所以dividend还大于0
dividend -= temp
#商要加对应的i
res += i
#倍数相应的要增加
i = i<<1
#目前的值也要不断的增加
temp = temp<<1
#判定正负号
if not positive:
res = -res
return min(max(-2147483648,res), 2147483647)

总的来说,这思路就是不断将dividend减少的while循环。总体循环分两层。外层用来控制最终跳出循环情况,同时它可以初始化逼近的间隔。内层是用来加快逼近速度的,你可以看到它是不断的2倍2倍的翻。所以总体思路和我一开始叠加的想法差不多,只不过它用了逼近的方法去提高自己的效率。所以这也是一种二分查找。


还有一种挺牛逼的解法,利用了python的特性:

 
 
class Solution :
def divide ( self , dividend , divisor ):
"""
:type dividend: int
:type divisor: int
:rtype: int
"""
sign = 1 if (dividend < 0 ) == (divisor < 0 ) else - 1
x, y = abs (dividend), abs (divisor)
if x < y:
return 0
if x == y:
return sign
#比较强大的思路以及优美的写法
#构建一个生成器,这个生成器以divisor为步长
arange = range (y, x, y)
alen = len (arange)
#判断临界情况
if arange[ - 1 ] + y <= x:
alen += 1
#正负
if sign == - 1 :
alen = - alen
return min (alen, 2 ** 31 - 1 )


接着是与上面思路类似的解法(题目没说不能用整除,但我觉得还是有钻空子的嫌疑,因为其他语言除法和整除是一样的符号)


class Solution:
    def divide(self, dividend, divisor):
        """
        :type dividend: int
        :type divisor: int
        :rtype: int
        """
        i = abs(dividend)//abs(divisor)
        if dividend > 0 and divisor < 0 or dividend < 0 and divisor > 0:
            i *= -1
        max_limit = 2**31 - 1
        if i < -2**31 or i > max_limit:
            return max_limit
        return i

总的来说,这期的精华还是二分查找。2个while的控制让我拍案叫绝。二分不一定是分,也可能是不断扩大2倍。学习了

猜你喜欢

转载自blog.csdn.net/weixin_41958153/article/details/80797415
今日推荐