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