Leetcode算法——29、两数相除

给定两个整数,作为除数和被除数,计算除法结果,不能使用乘法、除法和取模运算。

备注:
两个整数都是32位有符号整数。
除数不会为0。
假设我们的环境只能处理范围为 [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [231,2311]的整数。如果除法结果溢出,则返回 2 31 − 1 2^{31} − 1 2311

示例:

Example 1:
Input: dividend = 10, divisor = 3
Output: 3

Example 2:
Input: dividend = 7, divisor = -3
Output: -2

思路

1、除法定义

比如要计算 a 除以 b,则可以根据除法定义,寻找到 a 中包含了多少个 b:

定义一个累加和 sum = 0,每次在 sum 上累加一个 b,同时记录当前已经累加了多少个 b,直至 sum 超过了 a 为止。

此时 b 的累加个数 -1 即为除法结果。

2、改进版

同样是需要计算出 a 中包含了多少个 b,但是每次并不是只加一个除数,而是可以一次性加上n个除数,减少时间复杂度。

当然,前提是需要知道这n个除数之和,这个可以从前面的结果直接得到:比如上一步累加完之后,统计一共累加了 m 个 b 了,那么下一次可以直接在 sum 上累加 m 个 b,因为这 m 个 b 的值已经知道了。同理,下一次累加时,就知道了 2m 个 b 的累加值了,就可以直接累加 2m 个 b。

按照这个思路,是在 sum 依次累加 1 、 2 、 4 、 . . . 、 2 t 1、2、4、...、2^t 124...2t 个 b,每次累加的步长成指数上升,因此可以迅速使得 sum 接近 a。

但是在接近 a 时,需要反过来将步数慢慢减小,以免溢出,这时就要从 2 t , 2 t − 1 , . . . , 1 2^t, 2^{t-1},...,1 2t,2t1,...,1的顺序挨个试验,选择加上之后也不会使得 sum 超过 a 的累加值,最后满足 sum < a 但是 sum + b > a 即可。

python实现

def divide(dividend, divisor):
    """
    :type dividend: int
    :type divisor: int
    :rtype: int
    统计有多少个除数相加可以刚好超过被除数。
    """
    if dividend == 0:
        return 0
    
    #是否是正数
    is_positive = (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0)
    
    dividend = abs(dividend)
    divisor = abs(divisor)
    result = 0 # 除数的个数
    sum = 0 # 除数累加结果
    while(sum <= dividend):
        sum += divisor
        result += 1
    result -= 1
    if not is_positive:
        result = -result
    if result < -2**31 or result > 2**31 - 1:
        result = 2**31 - 1
    return result

def divide2(dividend, divisor):
    """
    :type dividend: int
    :type divisor: int
    :rtype: int
    改进版。
    """
    if dividend == 0:
        return 0
    
    #是否是正数
    is_positive = (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0)
    
    dividend = abs(dividend)
    divisor = abs(divisor)
    result = 0 # 除数的个数
    sum = 0 # 除数累加结果
    sum_list = [(1, divisor)] # 存放二元元组,第一位为一个正整数n,第二位为n个除数之和。
    while(True):
        have_pop = False
        while sum_list and sum + sum_list[-1][1] > dividend: # 优先累加最大的数,如果超过被除数,则改为较小数
            sum_list.pop()
            have_pop = True
        if not sum_list: # 所有可用加数都会溢出,则说明距离被除数的差已经不足一个除数了
            break
        sum += sum_list[-1][1]
        result += sum_list[-1][0]
        if not have_pop:
            sum_list.append((sum_list[-1][0]<<1, sum_list[-1][1]<<1))
    if not is_positive:
        result = -result
    if result < -2**31 or result > 2**31 - 1:
        result = 2**31 - 1
    return result
    
if '__main__' == __name__:
    dividend = 2147483647
    divisor = 1
    print(divide2(dividend, divisor))

你可能感兴趣的:(python,算法)