688. Knight Probability in Chessboard

题目

在这里插入图片描述
求一个象棋,马在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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值