前言:锻炼自己的思想,规范自己的编程思路。
问题:
在 n*m 大小的棋盘中,有黑白两种棋子,黑棋记作字母 "X", 白棋记作字母 "O",空余位置记作 "."。当落下的棋子与其他相同颜色的棋子在行、列或对角线完全包围(中间不存在空白位置)另一种颜色的棋子,则可以翻转这些棋子的颜色。
「力扣挑战赛」黑白翻转棋项目中,将提供给选手一个未形成可翻转棋子的棋盘残局,其状态记作 chessboard。若下一步可放置一枚黑棋,请问选手最多能翻转多少枚白棋。
注意:
若翻转白棋成黑棋后,棋盘上仍存在可以翻转的白棋,将可以 继续 翻转白棋 输入数据保证初始棋盘状态无可以翻转的棋子且存在空余位置
示例:(放代码里面)
输入:chessboard = ["....X.","....X.","XOOO..","......","......"]
输出:3
解释:
可以选择下在 [2,4] 处,能够翻转白方三枚棋子。
思路:
函数先声明 m 和n获取棋盘的行数和列数 ,并初始化变量 s 为 0。变量 s 用于存储最多能翻转多少枚白棋。然后定义一个二维数组 d,表示八个方向。
接下来,定义了一个名为 BFS 的内部函数,用于在给定位置放置黑棋并计算能翻转多少枚白棋。这个函数接受两个参数sx 和 sy,表示黑棋的位置。
在BFS 函数中,首先创建一个副本G 来存储棋盘状态。然后创建一个队列 q 并将黑棋的位置加入队列。将黑棋放置在给定位置,并初始化变量 t 为 0。变量t 用于存储当前位置能翻转多少枚白棋。
然后进入循环,每次从队列中取出一个位置 [x, y]。对于每个方向,计算下一个位置 [xx, yy] 并检查是否在棋盘内且为白棋。如果是,则继续沿着当前方向搜索,并累加计数器k。如果找到了黑棋,则将计数器累加到变量t中,并将中间的白棋翻转为黑棋。
当队列为空时,循环结束。更新最大翻转数量 s = Math.max(s, t)。
最后,在主函数中遍历整个棋盘,对于每个空位,调用 BFS 函数计算能翻转多少枚白棋。最后返回最大翻转数量 s。
基于上述思考,代码如下:
/**
* @param {string[]} chessboard
* @return {number}
*/
var flipChess = function(chessboard) {
const m = chessboard.length;
const n = chessboard[0].length;
let s = 0;
const d = [[1,0], [1,1], [0,1], [-1,1], [-1,0], [-1,-1], [0,-1], [1,-1]];
function BFS(sx, sy) {
let G = chessboard.map(row => row.split(''));
let q = [[sx, sy]];
G[sx][sy] = 'X';
let t = 0;
while (q.length) {
const [x, y] = q.shift();
for (let i = 0; i < 8; i++) {
const dx = d[i][0];
const dy = d[i][1];
let xx = x + dx;
let yy = y + dy;
let k = 0;
while (xx >= 0 && xx < m && yy >= 0 && yy < n && G[xx][yy] === 'O') {
xx += dx;
yy += dy;
k++;
}
if (xx >= 0 && xx < m && yy >= 0 && yy < n && G[xx][yy] === 'X') {
t += k;
while (k--) {
xx -= dx;
yy -= dy;
q.push([xx, yy]);
G[xx][yy] = 'X';
}
}
}
}
s = Math.max(s, t);
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (chessboard[i][j] === '.') {
BFS(i, j);
}
}
}
return s;
}
执行结果如下图: