题目:
给定两个整数,被除数 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。
思路:
既然不能用乘除法,可以换种思路,除法乘法其实就是变相的加减法。
我们可以从被除数减去除数,记录经历多少个multiple因子,即为我们需要的结果
方法一:
位运算辅助,核心思想是通过减法,同时倍增倍减因子模拟实现除法功能。
class Solution(object):
def divide(self, dividend, divisor):
"""
:type dividend: int
:type divisor: int
:rtype: int
"""
res = 0
MIN_INT, MAX_INT = -2147483648, 2147483647 # [−2**31, 2**31−1]
flag = 1 if dividend ^ divisor >= 0 else -1 #异或用来判断正负
dividend = (dividend + (dividend>>31))^(dividend>>31) #取绝对值
divisor = (divisor + (divisor>>31))^(divisor>>31) #取绝对值
res = 0
while dividend >= divisor:
cur,multiple = divisor,1
while dividend >= cur:
dividend -=cur
res +=multiple
multiple <<=1
cur <<=1
if flag<0:
res = ~res +1 #取相反数
return min(max(MIN_INT, res), MAX_INT)
方法二:
记录一下Orust题解的思路。
两种方法同一种思路,只不过不是用位运算进行操作。
递归:
class Solution(object):
def divide(self, dividend, divisor):
"""
:type dividend: int
:type divisor: int
:rtype: int
"""
MIN_INT, MAX_INT = -2147483648, 2147483647 # [−2**31, 2**31−1]
flag = 1 # 存储正负号,并将分子分母转化为正数
if dividend < 0: flag, dividend = -flag, -dividend
if divisor < 0: flag, divisor = -flag, -divisor
def div(dividend, divisor):
if dividend < divisor:
return 0
cur = divisor
multiple = 1
while cur + cur < dividend: # 用加法求出保证divisor * multiple <= dividend的最大multiple
cur += cur # 即cur分别乘以1, 2, 4, 8, 16...2^n,即二进制搜索
multiple += multiple
return multiple + div(dividend - cur, divisor)
res = div(dividend, divisor)
res = res if flag > 0 else -res # 恢复正负号
if res < MIN_INT: # 根据是否溢出返回结果
return MIN_INT
elif MIN_INT <= res <= MAX_INT:
return res
else:
return MAX_INT
迭代:
class Solution(object):
def divide(self, dividend, divisor):
"""
:type dividend: int
:type divisor: int
:rtype: int
"""
MIN_INT, MAX_INT = -2147483648, 2147483647
flag = 1
if dividend < 0:
flag, dividend = -flag, -dividend
if divisor < 0:
flag, divisor = -flag, -divisor
res = 0
while dividend >= divisor:
cur = divisor #第一次是cur = divisor
multiple = 1
while cur+cur < dividend:
cur += cur # 直接比较divisor x 2(加快比较速度)
multiple += multiple # 保留divisor的倍数,也就是我们需要累加的商
dividend -= cur # dividend 减除数divisor 进行下一轮while
res += multiple
res = res if flag >0 else -res #还原商的正负
if res < MIN_INT:
return MIN_INT
elif res > MAX_INT:
return MAX_INT
else:
return res