688马在棋盘上的概率
题目: 已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始。即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1),现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动,如下图所示,国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置.
来源: https://leetcode-cn.com/problems/knight-probability-in-chessboard/
法一: 自己的代码
思路: 写出状态转移方程,先记录每个格子在前N-1次不会跳出去的路径数,不断更新第N次的.
# 执行用时 :264 ms, 在所有 python3 提交中击败了37.50% 的用户 # 内存消耗 :12.8 MB, 在所有 python3 提交中击败了100.00%的用户 from typing import List class Solution: def knightProbability(self, N: int, K: int, r: int, c: int) -> float: # 记录前K-1次的状态 previous_status = [[1] * N for i in range(N)] # 记录八个方向 dirc = [[1,2],[1,-2], [2,1],[2,-1], [-1,2],[-1,-2], [-2,1],[-2,-1]] # 进行K次移动 for k in range(K): current_status = [[0] * N for i in range(N)] for i in range(N): for j in range(N): for d in dirc: p = d[0] + i q = d[1] + j # 如果超出边界了,则这次跳跃无效, if p < 0 or q < 0 or p >= N or q >= N: pass else: # 注意第一次的时候,previous_status为全1数组 # previous_status中记录的是前K-1次的状态,如第K-1次的时候,某个格子中的数是5, # 表示第K-1次跳的时候,有5种方法跳到该格子 current_status[i][j] = current_status[i][j] + previous_status[p][q] # current_status中现在记录的是前K-1回(跳了8的K-1次)的跳跃中,有多少次在棋盘内 previous_status = current_status return previous_status[r][c] / (8 ** K) if __name__ == '__main__': duixiang = Solution() a = duixiang.knightProbability(10, 13, 5, 3) print(a) print(8 ** 13)
受576出界的路径数启发的回溯法代码,同576一样不用lru_cache的话会超时.注意回溯后哪些参数需要恢复到回溯前的状态.
# 执行用时 :200 ms, 在所有 python3 提交中击败了70.45% 的用户 # 内存消耗 :22.6 MB, 在所有 python3 提交中击败了8.00%的用户 from functools import lru_cache from typing import List class Solution: def knightProbability(self, N: int, K: int, r: int, c: int) -> float: # 记录前K-1次的状态 previous_status = [[1] * N for i in range(N)] # 记录八个方向 dirc = [[1,2],[1,-2], [2,1],[2,-1], [-1,2],[-1,-2], [-2,1],[-2,-1]] @lru_cache(None) def recursion(i,j,K): # 如果出界了返回0 或次数用完了 if i < 0 or i >= N or j < 0 or j >= N or K < 0: return 0 # 否则在界内,如果次数恰好用完了,说明是一条完整的路径,返回1 elif K == 0: return 1 # 否则继续遍历 else: pass res = 0 for p,q in dirc: # 下面这样写是错的,回溯函数调用结束的时候,无法返回原先的坐标值i,j # i = i + p # j = j + q K -= 1 # 利用回溯函数的时候一定要注意哪些量在调用结束后,需要恢复成调用前的 res += recursion(i+p,j+q,K) K += 1 return res return recursion(i=r, j=c, K=K) / (8 ** K) if __name__ == '__main__': duixiang = Solution() a = duixiang.knightProbability(10, 13, 5, 3) print(a) print(8 ** 13)
法二: 官方代码
转移矩阵