[路飞]_leetcode 688. 骑士在棋盘上的概率

1,297 阅读1分钟

「这是我参与2022首次更文挑战的第30,活动详情查看:2022首次更文挑战

688. 骑士在棋盘上的概率

在一个 n x n 的国际象棋棋盘上,一个骑士从单元格 (row, column) 开始,并尝试进行 k 次移动。行和列是 从 0 开始 的,所以左上单元格是 (0,0) ,右下单元格是 (n - 1, n - 1) 。

象棋骑士有8种可能的走法,如下图所示。每次移动在基本方向上是两个单元格,然后在正交方向上是一个单元格。

image.png

每次骑士要移动时,它都会随机从8种可能的移动中选择一种(即使棋子会离开棋盘),然后移动到那里。

骑士继续移动,直到它走了 k 步或离开了棋盘。

返回 骑士在棋盘停止移动后仍留在棋盘上的概率 。

 

示例 1:

输入: n = 3, k = 2, row = 0, column = 0
输出: 0.0625
解释: 有两步(到(1,2),(2,1))可以让骑士留在棋盘上。
在每一个位置上,也有两种移动可以让骑士留在棋盘上。
骑士留在棋盘上的总概率是0.0625。

示例 2:

输入: n = 1, k = 0, row = 0, column = 0
输出: 1.00000  

提示:

1 <= n <= 25
0 <= k <= 100
0 <= row, column <= n

分析

我们从题目可以得到棋盘为 n*n、我们需要走k步、我们的起始坐标为[row, column]、棋子行走方向为8种,需要求出棋子在棋盘上的概率。我们在行走过程中每走一步都需要再上一步概率的基础上除以8再乘以在棋盘上的个数。

可以通过遍历出现棋盘行走的全部情况,这样就方便我计算当前情况在棋盘上的概率。但这样我们会计算出很多垃圾数据,但好在n与k的范围都比较小。要计算出所有情况我们就需要从三个维度出发步骤、行坐标、列坐标。

说完暴力的方法我们再来说说在什么情况下棋子会超出棋盘范围。当棋子坐标与棋子的行走偏移量之和小于 0 或者大于等于 n 的时候就说明棋子已经超出棋盘范围了。

我们再来说说棋子行的8个方向从图中:

image.png

我们可以得出这个8个方向的行走偏移量分别为(-2, -1)、(-2, 1)、(2, -1)、(2, 1)、(-1, -2)、(-1, 2)、(1, -2)、(1, 2)。

分步实现'

定义变量记录棋子行走的8个方向

const dirs = [[-2, -1], [-2, 1], [2, -1], [2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2]];

根据步骤、行坐标、列坐标初始化棋盘概率数组

var createActionRecord = function(n,k){
    return new Array(k + 1).fill(0).map(() => new Array(n).fill(0).map(() => new Array(n).fill(0)));
}

我第一次放棋子的时候肯定是都在棋盘上的,所有将步骤为0的概率全部设置为1

var initStep1 = function(actionRecord,n){
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            actionRecord[0][i][j] = 1;
        }
    }
}

每走一步就计算当前步骤的所有情况,这里我们通过三个维度+8个方法当在范围0 <= i < n

var handleAction = function(actionRecord, n, k ,dirs){
    for (let step = 1; step <= k; step++) { 
        for (let i = 0; i < n; i++) {
            for (let j = 0; j < n; j++) {
                for (const dir of dirs) {
                    const ni = i + dir[0]
                    const nj = j + dir[1]
                    if (ni >= 0 && ni < n && nj >= 0 && nj < n) {
                        actionRecord[step][i][j] += actionRecord[step - 1][ni][nj] / 8;
                    }
                }
            }
        }
    }
}

完整代码

/**
 * @param {number} n
 * @param {number} k
 * @param {number} row
 * @param {number} column
 * @return {number}
 */

var knightProbability = function(n, k, row, column) {
    const dirs = [[-2, -1], [-2, 1], [2, -1], [2, 1], [-1, -2], [-1, 2], [1, -2], [1, 2]];
    const actionRecord = createActionRecord(n,k);
    initStep1(actionRecord,n)
    handleAction(actionRecord, n, k ,dirs)
    return actionRecord[k][row][column];
};
var createActionRecord = function(n,k){
    return new Array(k + 1).fill(0).map(() => new Array(n).fill(0).map(() => new Array(n).fill(0)));
}
var initStep1 = function(actionRecord,n){
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < n; j++) {
            actionRecord[0][i][j] = 1;
        }
    }
}
var handleAction = function(actionRecord, n, k ,dirs){
    for (let step = 1; step <= k; step++) { 
        for (let i = 0; i < n; i++) {
            for (let j = 0; j < n; j++) {
                for (const dir of dirs) {
                    const ni = i + dir[0]
                    const nj = j + dir[1]
                    if (ni >= 0 && ni < n && nj >= 0 && nj < n) {
                        actionRecord[step][i][j] += actionRecord[step - 1][ni][nj] / 8;
                    }
                }
            }
        }
    }
}