我必须创建一个解决楼梯问题的程序,其中我必须设计n
砖块数的楼梯。复杂性在于每个步骤中的砖块数量必须唯一,并且少于上一步。
例如,使用6块积木,我可以制作阶梯高度为(5,1) , (4,2) and (3,2,1)
而不是(3,3) or (1,2,3) or (2,4)
或任何其他排列的楼梯。
我已经设计了代码,但是问题在于,直到n
为止,它可以正常运行接近100或120,但是如果输入大于这些值,则冻结。我是Python编程和学习概念的初学者。
我尝试了记忆,但无济于事。我需要知道是否还有其他方法可以使我的代码更优化以在n
上以200-250的速度运行?
import cProfile
def solution(n):
memory = {0: [], 1: [1], 2: [2]}
def rec(max_val, i):
t = []
r = []
for j in range(1,i):
y = i - j
if y < max_val:
if y > j:
t = [y, j]
r.append(t)
if n / 2 >= j >= 3 and j in memory:
mem = memory[j]
[r.append([y, item]) for item in mem]
else:
if y >= 3 and n / 2 >= j >= 3 and j in memory:
mem = memory[j]
for item in mem:
if y > item[0]:
r.append([y, item])
else:
v = rec(y, j)
if v:
for item in v:
t = [y, item]
r.append(t)
if r:
if i in memory:
if len(memory[i]) < len(r):
memory[i] = r
else:
memory[i] = r
return r
def main_func(n):
stair = []
max_val = 201
total = 0
for i in range (1,n):
x = n - i
if x > i:
s = [x, i]
total += 1
if i >= 3:
u = rec(max_val, i)
total += len(u)
elif x == i and i >= 3:
u = rec(max_val, i)
total += len(u)
elif x < i and i >= 3:
u = rec(x, i)
total += len(u)
return total
stairs = main_func(n)
return (stairs)
print(solution(100))
答案 0 :(得分:0)
您可以从楼梯底部的角度递归解决问题。该策略是针对每个基本大小对下一步级别的模式计数进行累加。
例如,对于6个积木,第一个调用将遍历基本大小n = 5,4,3,2,然后进行递归调用,以了解使用剩余的积木和最大底数为n-1。下一级计数的总和将构成可能的楼梯样式的总数。
在楼梯的顶部,您至少需要3块砖才能添加一个以上的级别,这样,如果剩余的砖块少于3个,则可以停止递归计数,计数为1。这样,就可以将递归调用汇总起来,形成更大的总数,并在原始调用完成后产生正确的答案。
为了优化此过程,您可以使用备忘录,也可以使用每次递归提供的基本大小来缩短计算时间。
对于给定的基数,可以使用的最大块数将是1到该基数的和。可以使用高斯公式base*(base+1)/2
计算得出。如果您所用的块数多于该基数的最大块数,则可以停止递归并返回零计数(因为剩余的块数太多,并且无法在先前级别的基数上全部容纳它们)< / p>
另一种优化计算的方法是按降序循环基本大小。这样一来,您可以在下一级别的计数为零时立即停止循环,这意味着该基本大小(或任何较小的基本大小)的剩余砖块过多
这是一个示例(使用lru_cache进行记忆):
from functools import lru_cache
@lru_cache(None)
def stairCount(N,base=None):
base = min(base or N-1,N)
if N > base*(base+1)//2: return 0
if N < 3: return 1
count = 0
while True:
nextLevels = stairCount(N-base,base-1)
if nextLevels == 0: break
count += nextLevels
base = base - 1
return count
通过这些优化,该功能将在不到一秒钟的时间内响应600砖(取决于计算机的速度)。
有了Python的列表解析功能,您可以更简洁地编写此函数(尽管它将失去递减的基本顺序优化≈10%):
@lru_cache(None)
def stairCount(N,base=None):
base = min(base or N-1,N)
if N > base*(base+1)//2: return 0
if N < 3: return 1
return sum(stairCount(N-b,b-1) for b in range(2,base+1))
编辑:这是带有“手动”记忆的版本(即不使用functools):
def stairCount(N,base=None,memo=dict()):
memoKey = (N,base)
if memoKey in memo: return memo[memoKey]
base = min(base or N-1,N)
if N > base*(base+1)//2: return 0
if N < 3: return 1
count = 0
while True:
nextLevels = stairCount(N-base,base-1,memo)
if nextLevels == 0: break
count += nextLevels
base = base - 1
memo[memoKey] = count
return count