「这是我参与2022首次更文挑战的第30,活动详情查看:2022首次更文挑战」
688. 骑士在棋盘上的概率
在一个 n x n 的国际象棋棋盘上,一个骑士从单元格 (row, column) 开始,并尝试进行 k 次移动。行和列是 从 0 开始 的,所以左上单元格是 (0,0) ,右下单元格是 (n - 1, n - 1) 。
象棋骑士有8种可能的走法,如下图所示。每次移动在基本方向上是两个单元格,然后在正交方向上是一个单元格。
每次骑士要移动时,它都会随机从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个方向从图中:
我们可以得出这个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;
}
}
}
}
}
}