簡體   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