题目
求一个象棋,马在n*n的棋盘上从(r,c)开始,随机走k步的概率不会走出棋盘的概率。
我的代码(尝试使用递归暴力破解失败)
class Solution:
def knightProbability(self,N,K,r,c):
if K==0:
return 1.0
count=0
if K==1:
if r+2<N and c+1<N:
count+=0.125
if r+2<N and c-1>=0:
count+= 0.125
#print(2)
if c+2<N and r+1<N:
count+=0.125
#print(3)
if c+2<N and r-1>=0:
count+=0.125
#print(4)
if c-2>=0 and r+1<N:
count+=0.125
#print(5)
if c-2>=0 and r-1>=0:
count+=0.125
#print(6)
if r-2>=0 and c+1<N:
count+=0.125
#print(7)
if r-2>=0 and c-1>=0:
count+=0.125
# print(8)
else:
if r+2<N and c+1<N:
count+=0.125*self.knightProbability(N,K-1,r+2,c+1)
if r+2<N and c-1>=0:
count+=0.125*self.knightProbability(N, K-1, r+2, c-1)
if c+2<N and r+1<N:
count+=0.125*self.knightProbability(N, K-1, r+1, c+2)
if c+2<N and r-1>=0:
count+=0.125*self.knightProbability(N, K-1, r-1, c+2)
if c-2>=0 and r+1<N:
count+=0.125*self.knightProbability( N, K-1, r+1, c-2)
if c-2>=0 and r-1>=0:
count+=0.125*self.knightProbability( N, K-1, r-1, c-2)
if r-2>=0 and c+1<N:
count+=0.125*self.knightProbability( N, K-1, r-2, c+1)
if r-2>=0 and c-1>=0:
count+=0.125*self.knightProbability( N, K-1, r-2, c-1)
#print(count)
return count
改进版本
查询了相关的思路得到了改进版本。
效率很低的地方:
在一个棋盘上很多个点被我们重复走过,重复计算,我们可以使用哈希表将走过点的值记录下来,如果在表中即查表即可。
还有一个问题就是:代码不够简短
使用for x,y in …这样的语句可以改进我的代码。
class Solution:
def knightProbability(self, N, K, r, c):
memo = {}
def dfs(i, j, p, k):
if 0 <= i < N and 0 <= j < N and k < K:
sm = 0
for x, y in ((-1, -2), (-2, -1), (-2, 1), (-1, 2), (1, 2), (2, 1), (2, -1), (1, -2)):
if (i + x, j + y, k) not in memo:
memo[(i + x, j + y, k)] = dfs(i + x, j + y, p / 8, k + 1)
sm += memo[(i + x, j + y, k)]
return sm
else:
return 0 <= i < N and 0 <= j < N and p or 0
return dfs(r, c, 1, 0)
高效代码(进阶版)
大概思路是建立两个矩阵大概只有原来1/4 互换? 总体的思路就是利用了棋盘的对称性。但如何使用,并没有什么太多理解。
class Solution:
def knightProbability(self, n: 'int', k: 'int', x: 'int', y: 'int') -> 'float':
if not k:
return 1.0
if not n or n <= 1:
return 0.0
# 处理掉两种特殊情况。
m = n + 1 >> 1
# 大小为n的一半,即创建的矩阵约为原来1/4
pre = [[1] * m for _ in range(m)]
cur = [[0] * m for _ in range(m)]
# 创建一个pre矩阵/和cur矩阵。
delta = (
(-1, -2), ( 1, -2),
(-1, 2), ( 1, 2),
(-2, -1), ( 2, -1),
(-2, 1), ( 2, 1),
)
def prob(i, j):
if not (0 <= i < n and 0 <= j < n):
return 0
if i << 1 >= n:
i = n - 1 - i
if j << 1 >= n:
j = n - 1 - j
return pre[i][j] if i < j else pre[j][i]
for _ in range(k - 1):
for i in range(m):
for j in range(i, m):
cur[i][j] = sum(prob(i + di, j + dj) for di, dj in delta) / 8.0
pre, cur = cur, pre
return sum(prob(x + di, y + dj) for di, dj in delta) / 8.0