我正在解决的问题是Cracking the Coding Interview:
"一个孩子正在爬楼梯,有n个台阶,可以跳一步,两步, 或一次3个步骤。实现一种方法来计算有多少可能的方法 孩子可以跑上楼梯。"
来自C ++我知道计数器可以作为参考传递,但是在python中你不能。我也试图跟踪导致成功的步骤顺序。我正在编写这样的代码:
def __calculatePaths(currPathLength, paths, currSeries):
if currPathLength == 0:
print "successful series is", currSeries
return 1
elif currPathLength < 0: return 0
for i in range(1, 4):
newSeries = list(currSeries) # make new series to track steps
newSeries.append(i)
paths += __calculatePaths(currPathLength - i, paths, newSeries)
return paths
def calculatePaths(pathLength):
paths = __calculatePaths(pathLength, 0, [])
return paths
if __name__ == '__main__':
calculatePaths(3)
此次通话的输出为:
successful series is [1, 1, 1]
successful series is [1, 2]
successful series is [2, 1]
successful series is [3]
6
我很困惑,因为我的程序获得了正确的路径序列,但路径数量错误。我应该如何增加我的路径?我知道如何在没有全局变量的情况下做到这一点,但我无法在不使用全局变量的情况下解决这个问题。谢谢!
答案 0 :(得分:1)
最重要的是,要意识到你不必确定那些序列:你只需要计算它们。例如,从步骤N-1开始只有一种方法:跳1步。从N-2开始,有两种方法:一次跳两个步骤,或者从那里跳一步并完成。我们的完成方式&#34; list现在看起来像这样,向后工作:
way = [1, 2, ...]
现在,看看步骤N-3会发生什么。我们最终有3个选择:
总共有2 + 1 + 1或4种方式完成。
初始化我们的算法。现在为复发关系。初始列表如下所示:
way = [1, 2, 4, ...]
从现在开始,我们无法单跳到顶部。相反,我们必须依赖于我们上面的三个步骤。我们从步骤N-J中做出的选择是:
因此,对于所有j&gt; = 3:
way[j] = way[j-1] + way[j-2] + way[j-3]
这为您提供 O(N)时间的解决方案。
答案 1 :(得分:0)
在函数__calculatePaths中,必须在for循环之前设置paths = 0。否则,它会将值添加到路径的全局实例中,这就是您得错答案的原因。
def __calculatePaths(currPathLength, paths, currSeries):
if currPathLength == 0:
print "successful series is", currSeries
return 1
elif currPathLength < 0: return 0
paths = 0
for i in range(1, 4):
newSeries = list(currSeries) # make new series to track steps
newSeries.append(i)
paths += __calculatePaths(currPathLength - i, paths, newSeries)
return paths
def calculatePaths(pathLength):
paths = __calculatePaths(pathLength, 0, [])
return paths
if __name__ == '__main__':
calculatePaths(3)
您可以以非常有效的方式获得多种方式。在O(N)中使用动态编程。甚至更有效地使用矩阵求幂O(logN)。
答案 2 :(得分:0)
这应该是使用您的解决方案进行计算的最有效方式:
from collections import deque
def calculate_paths(length):
count = 0 # Global count
def calcuate(remaining_length):
# 0 means success
# 1 means only 1 option is available (hop 1)
if remaining_length < 2:
nonlocal count # Refer to outer count
count += 1
return
# Calculates, removing the length already passed.
# For 1...4 or remaining_length+1 if it's less than 4.
# deque(, maxlen=0) is the fastest way of consuming an iterator
# without also keeping it's data. This is the most efficient both
# memory-wise and clock-wise
deque((calcuate(remaining_length-i)
for i in range(1, min(4, remaining_length+1))), maxlen=0)
calcuate(length)
return count
>>> calculate_paths(2)
2
>>> calculate_paths(3)
4
>>> calculate_paths(4)
7
正如您所看到的,没有必要保留路径,因为只剩下剩余的长度很重要。
@ Prune的答案有更好的算法。在这里实施:
def calculate_paths(length):
results = deque((1, 2, 4), maxlen=3)
if length <= 3:
return results[length-1]
for i in range(3, length):
results.append(sum(results))
return results.pop()
消除递归也会导致使用较少的帧,并且不会因最大递归而停止。