该除法函数(不使用除法或乘法运算符)的时间复杂度是多少?

时间:2019-05-22 20:59:56

标签: python-3.x algorithm bitwise-operators division bit-shift

我解决了这个leetcode问题https://leetcode.com/problems/divide-two-integers/。目的是在不使用乘法或除法运算符的情况下获得dividend除以divisor的商。这是我的解决方案:

    def divide(dividend, divisor):     
        """
        :type dividend: int
        :type divisor: int
        :rtype: int
        """
        sign = [1,-1][(dividend < 0) != (divisor < 0)]
        dividend, divisor = abs(dividend), abs(divisor)
        res = 0
        i = 0
        Q = divisor
        while dividend >= divisor:
            dividend = dividend - Q
            Q <<= 1
            res += (1 << i)
            i+=1
            if dividend < Q:
                Q = divisor
                i = 0

        if sign == -1:
            res = -res

        if res < -2**31 or res > 2**31 -1:
            return 2**31 - 1

        return res

因此,我在分析此解决方案的时间复杂性时遇到了麻烦。我知道应该是O(log(something))。通常对于算法,我们说每次迭代将输入除以2时,它们就是O(log(n)),但是在这里,我将每次迭代将divisor乘以2 Q<<= 1,因此在每一步中,我都要迈向解决方案。显然,如果dividend对于更大的divisor是相同的,我的算法将更快。同样,dividend的{​​{1}}越大,我们的运行时间就越慢。

我的猜测是,控制该算法运行时间的方程式基本上是O(dividend / divisor)(除法的除法运算)形式,其中有一些登录信息,这说明我在每一步中将divisor乘以2 Q ...我不知道到底是什么。

编辑:

当我第一次发布问题时,我发布的算法是下面的算法,Alain Merigot的答案基于该算法。顶部版本与顶部版本之间的区别是,我的分红永远都不会低于0,从而缩短了运行时间。

Q <<= 1

2 个答案:

答案 0 :(得分:1)

最坏情况下的复杂性很容易找到。

每次迭代都会生成一个结果位,并且迭代次数等于商中的位数。

当除法器= 1时,商=除数,在这种情况下,迭代次数等于前导(最高有效位)1之后的除数中的位数。当除数= 2 ^(n-1)时,该值最大化。 + k,其中n是位数,而k是任意数,例如1≤k<2 ^(n-1)。这显然是最坏的情况。

第一次迭代后,p股息= dividend-diviser(= dividend-1)和diviser = 2 ^ 1

在迭代m之后,diviser = 2 ^ m和被除数= dividend-(1 + 2 ^ 1 + .. + 2 ^(m-1))=被除数-(2 ^ m-1)

当红利<0时,迭代停止。当p = 2 ^(n-1)+ k,且k> 0时,则发生在m = n。

因此,最坏情况下的步数为n,复杂度与被除数的位数呈线性关系。

答案 1 :(得分:1)

在最坏的情况下,您的算法为O(m ^ 2),其中m是结果中的位数。就输入而言,它将是O(log(dividend / divisor)^ 2)。

要了解原因,请考虑循环的作用。令a =股息,b =除数。只要循环足够大,循环就会从a中减去b,2b,4b,8b,...,然后一次又一次地重复此序列,直到a<b

它可以等效地写成两个嵌套循环:

while dividend >= divisor:
    Q = divisor
    i = 0
    while Q <= dividend:
        dividend = dividend - Q
        Q <<= 1
        res += (1 << i)
        i+=1

对于外部循环的每次迭代,内部循环将执行较少的迭代,因为dividend较小。在最坏的情况下,内循环对于外循环的每次迭代只会减少一次迭代。当结果是n的1 + 3 + 7 + 15 + ... +(2 ^ n-1)时,会发生这种情况。在这种情况下,可以证明n = O(log(res())),但是内部循环迭代的总数为O(n ^ 2),即结果的大小是二次方。

要使结果大小线性化,请首先计算Qi的最大所需值。然后从中倒退,从i中减去1,并在每次迭代中向右移Q。这样可以保证总共不超过2n次迭代。