问题描述
假设有排成一行的N个位置,记为1-N,N一定大于或者等于2,开始时机器人在其中的M位置上(M一定是1-N中的一个);
如果机器人来到1位置,那么下一步只能往右到2位置;
如果在N位置,下一步只能到N-1位置;
如果在中间位置,下一步可以往左或右;
规定机器人必须走K步,最终来到P位置(P在1-N之间);
给定四个参数N、M、K、P,返回方法数。
解决思路
首先考虑递归实现,暴力递归,设当前的位置为 cur,剩余步数为 rest,那不函数初始调用的参数就分别为:M、K。
考虑递归的优化,如果某次来到的cur和rest,之前已出现过,则可以利用之前的结果,因此考虑将中间结果缓存起来,即记忆式搜索。
继续优化,发现二维数组的某个值可以完全由其邻居推断出来,即完全动态规划。
三种方案的代码实现如下:
class RobotWalk:
"""
机器人走路步数
"""
def solution1(self, N, start, aim, K):
"""
:param N: N个位置,记为1-N,N一定大于或者等于2
:param start: 开始时机器人在其中的start位置上
:param aim: 最终来到的位置
:param K: 总过需要走K步
:return: 多少种走法
"""
if N < 2 or start < 1 or start > N or aim < 1 or aim > N or K < 1:
return -1
return self.process1(start, K, aim, N)
def process1(self, cur, rest, aim, N):
"""
:param cur: 机器人当前来到的位置是cur
:param rest: 机器人还有rest步需要去走
:param aim: 最终的目标是aim
:param N:
:return:
"""
if rest == 0:
return 1 if cur == aim else 0
if cur == 1:
return self.process1(2, rest-1, aim, N)
if cur == N:
return self.process1(N-1, rest-1, aim, N)
return self.process1(cur-1, rest-1, aim, N) + self.process1(cur+1, rest-1, aim, N)
def solution2(self, N, start, aim, K):
"""
递归 --> 记忆式搜索【弱动态规划】
:param N:
:param start:
:param aim:
:param K:
:return:
"""
if N < 2 or start < 1 or start > N or aim < 1 or aim > N or K < 1:
return -1
dp = [[-1]*(K+1) for _ in range(N+2)]
return self.process2(start, K, aim, N, dp)
def process2(self, cur, rest, aim, N, dp):
"""
:param cur:
:param rest:
:param aim:
:param N:
:param dp: 空间换时间,减少重复计算
:return:
"""
if dp[cur][rest] != -1:
return dp[cur][rest]
# 之前没算过!
if rest == 0:
ans = 1 if cur == aim else 0
elif cur == 1:
ans = self.process2(2, rest - 1, aim, N, dp)
elif cur == N:
ans = self.process2(N - 1, rest - 1, aim, N, dp)
else:
ans = self.process2(cur-1, rest-1, aim, N, dp) + self.process2(cur+1, rest-1, aim, N, dp)
# 更新数组
dp[cur][rest] = ans
return ans
def solution3(self, N, start, aim, K):
"""
记忆式搜索【弱动态规划】--> 强动态规划
:param N:
:param start:
:param aim:
:param K:
:return:
"""
if N < 2 or start < 1 or start > N or aim < 1 or aim > N or K < 1:
return -1
dp = [[0] * (K + 1) for _ in range(N + 1)]
dp[aim][0] = 1
for rest in range(1, K+1):
dp[1][rest] = dp[2][rest-1]
for cur in range(2, N):
dp[cur][rest] = dp[cur-1][rest-1] + dp[cur+1][rest-1]
dp[N][rest] = dp[N-1][rest-1]
return dp[start][K]