zoukankan      html  css  js  c++  java
  • 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)
    View Code

    受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)
    View Code

    法二: 官方代码

    转移矩阵

  • 相关阅读:
    堆排序
    如何在.Net中使用MongoDB
    二叉树遍历 C#
    对C# 中Readonly的再认识
    对C# 构造函数的理解
    TypeScript学习: 九、TypeScript的泛型
    TypeScript学习: 八、TypeScript的属性接口用法封装ajax
    锚点跳转不改变History
    设计模式笔记—代理模式
    小程序开发二:上手第一个小程序
  • 原文地址:https://www.cnblogs.com/xxswkl/p/12112683.html
Copyright © 2011-2022 走看看