繁体   English   中英

降低简单循环的时间/空间复杂度

[英]Reduce time /space complexity of simple loop

所以基本上,如果我在 python 中有这样的迭代,我已经编辑了问题以包含我的完整代码

class Solution:
    def myPow(self, x: float, n: int) -> float:
        temp = [];
        span = range(1,abs(n))
        if n ==0:
            return 1
        if abs(n)==1:
            temp.append(x)
        else:
            for y in span:
                if y == 1:
                    temp = []
                    temp.append(x*x)
                else:
                    temp.append(temp[-1] * x)
        if(n < 0):
            return 1/temp[-1]
        else:
            return temp[-1]

问题链接是: Pow(x,n)-leetcode我如何修改它以节省 memory 和时间。 我可以使用另一种数据结构吗? 我正在学习 python....

----------编辑------------ 我修改了代码以使用变量而不是临时数据列表

class Solution:
    def myPow(self, x: float, n: int) -> float:
        span = range(1,abs(n))
        if n ==0:
            return 1
        if abs(n)==1:
            temp = x
        else:
            for y in span:
                if y == 1:
                    temp = x*x
                else:
                    temp = temp * x
        if(n < 0):
            return 1/temp
        else:
            return temp

我的时间复杂度仍然有问题。 它适用于许多测试用例,但是当它尝试以 x = 0.00001 和 n = 2147483647 运行时。出现时间限制问题

为了降低时间复杂度,您可以通过取x的 2 次方并将指数除以 2 来划分每次的工作。 这形成了一个对数时间算法,因为指数在每一步都减半。

考虑以下示例:

10^8 = 10^(2*4) = (10^2)^4 = (10*10)^4

现在,有一种极端情况。 当指数为奇数时,您不能用 integer 将其除以 2。因此,在这种情况下,您需要将结果再乘以底数一次。

下面是上述思路的直接递归实现:

class Solution:
    def myPow(self, x: float, n: int) -> float:
        sign = -1 if n < 0 else 1
        n = abs(n)
        
        def helper(x, n):
            if n == 1: return x
            if n == 0: return 1
            
            if n % 2 == 1:
                return helper(x*x, n // 2) * x
            else:
                return helper(x*x, n // 2)
        
        res = helper(x, n)
        if sign == -1:
            return 1/res
        else:
            return res

请注意,我们已经获取了指数的abs并存储了符号并在最后处理它。

不要从 1 迭代到n ,而是使用分而治之:将指数除以 2 并使用递归来获得该幂,然后将该结果平方。 如果n是奇数,则再乘以x一次:

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n == 0:
            return 1
        if n == 1:
            return x
        if n < 0:
            return self.myPow(1/x, -n)
        temp = self.myPow(x, n // 2)
        temp *= temp
        if n % 2:
            temp *= x
        return temp

一个简单天真的解决方案可能是:

def myPow(x: float, n: int) -> float:
    ## -----------------------
    ## if we have a negative n then invert x and take the absolute value of n
    ## -----------------------
    if n < 0:
        x = 1/x
        n = -n
    ## -----------------------

    retval = 1
    for _ in range(n):
        retval *= x
    return retval

虽然这在技术上可行,但您将等到奶牛回家才能获得以下结果:

x = 0.00001 and n = 2147483647

所以我们需要找到一条捷径。 让我们考虑 2^5。 我们的天真方法会将其计算为:

(((2 * 2) * 2) * 2) * 2 == 32

但是,如果我们以不同的方式将一些东西组合在一起,我们可能会观察到这个问题:

(2 * 2) * (2 * 2) * 2 == 32

相似地:

((2 * 2) * (2 * 2) * 2) * ((2 * 2) * (2 * 2) * 2) == 32 * 32 = 1024

我们可能会观察到我们在技术上只需要计算

(2 * 2) * (2 * 2) * 2 == 32

一次并使用它两次得到 2^10。

同样我们只需要计算:

2 * 2 = 4

一次并使用它两次得到 2^5....

这向我暗示了递归。

让我们修改我们第一次尝试使用这种分而治之的方法。

def myPow2(x: float, n: int) -> float:
    ## -----------------------
    ## if we have a negative n then invert x and take the absolute value of n
    ## -----------------------
    if n < 0:
        x = 1/x
        n = -n
    ## -----------------------

    ## -----------------------
    ## We only need to calculate approximately half the work and use it twice
    ## at any step.
    ## -----------------------
    def _recurse(x, n):
        if n == 0:
            return 1
        res = _recurse(x, n//2) # calculate it once
        res = res * res # use it twice
        return res * x if n % 2 else res # if n is odd, multiple by x one more time (see 2^5 above)
    ## -----------------------

    return _recurse(x, n)

现在让我们试试:

print(myPow2(2.0, 0))
print(myPow2(2.0, 1))
print(myPow2(2.0, 5))
print(myPow2(2.1, 3))
print(myPow2(2.0, -2))
print(myPow2(0.00001, 2147483647))

这给了我:

1
2.0
32.0
9.261000000000001
0.25
0.0

如果你必须循环,你就必须大步跑,没有什么可以做的。 python 中的循环很慢。 那就是说您可能不必循环,如果您确实必须循环,则可以将此循环推送到高度优化的内部 function。告诉我们您正在尝试做什么(而不是您认为必须这样做,将元素附加到 lis 可能需要也可能不需要)。 永远记住程序优化的两条规则 一般规则:不要这样做。 专家规则:先不要做。 在让它变快之前让它工作,谁知道呢,它可能已经足够快了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM