我试图找出在给定的x,y和z下可能的排列总数。 x是初始数字,y是最终数字,z是按下的按钮总数。 我只能像国际象棋中的骑士那样从一个数字移动到另一个数字,呈“L”形。 例如,如果你刚刚拨了1,那么下一个号码必须是6或8。如果你刚拨了6,下一个号码一定是1或7。 目前,我的实现输出了我给出的所有数字的正确答案。但是,它的速度非常慢,因为计算时间是指数级的。我想知道的是如何在线性时间内,或多或少地计算这个。z将始终介于1和100之间(包括1和100)。你知道吗
##Computes the number of phone numbers one
##can dial that start with the digit x, end
##in the digit y, and consist of z digits in
##total. Output this number as a
##string representing the number in base-10.
##Must follow "knights rule" moves, like chess
##########_________##########
##########|1||2||3|##########
##########|_||_||_|##########
##########|4||5||6|##########
##########|_||_||_|##########
##########|7||8||9|##########
##########|_||_||_|##########
##########|_||0||_|##########
##########^^^^^^^^^##########
dict = {0: [4, 6], 1: [6, 8], 2: [7, 9], 3: [4, 8],
4: [0, 3, 9], 5: [], 6: [0, 1, 7], 7: [2, 6], 8: [1, 3],
9: [2, 4]}
def recAnswer(current, y, z, count, total):
if count == z and current == y:
total += 1
return total
count+=1
if count > z:
return total
for i in dict.get(current):
total = recAnswer(i, y, z, count, total)
return total
def answer(x, y, z):
if x == y:
if z%2 == 0:
return '0'
elif x == 5 or y == 5:
if z == 1 and x == y:
return '1'
else:
return '0'
elif x%2 != 0 and y%2 == 0:
if z%2 != 0:
return '0'
elif x%2 == 0 and y%2 != 0:
if z%2 != 0:
return '0'
elif x%2 == 0 and y%2 ==0:
if z%2 == 0:
return '0'
elif x%2 != 0 and y%2 != 0:
if z%2 == 0:
return '0'
total = recAnswer(x,y,z,1,0)
return str(total)
def test():
for i in xrange(1,15,1):
print i,":",answer(1,3,i)
print answer(6, 2, 5)
print answer(1, 6, 3)
print answer(1, 1, 99)
test()
从codereview
代码运行缓慢的原因是,您会一次又一次地访问(并重新计算)相同的组合。你可以用一种叫做记忆的技术来缩短重新计算的部分。你知道吗
记忆化很容易添加,但是让我们重新设计递归函数,以便调用函数进行累加,而不是函数本身。换句话说,不要传递总计,只返回此子路径的组合:
这种变化不会改变计算本身;结果仍然是一样的。你知道吗
现在让我们把对同一个参数的所有重复调用都缩短。我们将字典
memo
传递给函数。这个dict的键是函数参数的元组。作为递归函数的第一步,检查计算是否已经完成。作为初始计算的最后一步,将解决方案添加到dict中:用一个空的dict开始计算,当然:
附录:现在我已经了解了
@decorator
的内容,我将用memoization来修饰函数,这样就不会改变原来的函数。好吧,我还要做一个修改,正如Janne在评论中提到的:我将把target cound和current count合并成一个变量,这个计数从目标值开始,倒计时到零,而不是倒计时到目标值。你知道吗首先是memoization decorator,它将是一个包含修饰函数
func
和memoization字典的类。此类必须使用所需数量的参数实现函数__call__
:现在是在
def
初始化之前使用decorator的简化函数:@memoized
修饰符通过memoized.__call__
调用函数recAnswer
,该函数处理记忆化。按如下方式调用递归函数:(这里的-1考虑到在原始代码中,计数从1开始。)
可能还有改进的余地。例如,可以使用splat语法设置
memoized
decorator类变量的参数数,以便可以将memoizer重新用于其他函数:所有这一切的结果是,如果你有一个问题,你重新评估同一组参数一次又一次,简单地跟踪以前计算的结果可以给你一个巨大的速度,而不必摆弄基本的实现。你知道吗
相关问题 更多 >
编程相关推荐