[英]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.