可以攻击国王的皇后
题目
在一个 8x8 的棋盘上,放置着若干「黑皇后」和一个「白国王」。
给定一个由整数坐标组成的数组 queens
,表示黑皇后的位置;以及一对坐标 king
,表示白国王的位置,返回所有可以攻击国王的皇后的坐标(任意顺序)。
示例 1:
输入:queens = [[0,1],[1,0],[4,0],[0,4],[3,3],[2,4]], king = [0,0]
输出:[[0,1],[1,0],[3,3]]
解释:
[0,1] 的皇后可以攻击到国王,因为他们在同一行上。
[1,0] 的皇后可以攻击到国王,因为他们在同一列上。
[3,3] 的皇后可以攻击到国王,因为他们在同一条对角线上。
[0,4] 的皇后无法攻击到国王,因为她被位于 [0,1] 的皇后挡住了。
[4,0] 的皇后无法攻击到国王,因为她被位于 [1,0] 的皇后挡住了。
[2,4] 的皇后无法攻击到国王,因为她和国王不在同一行/列/对角线上。
示例 2:
输入:queens = [[0,0],[1,1],[2,2],[3,4],[3,5],[4,4],[4,5]], king = [3,3]
输出:[[2,2],[3,4],[4,4]]
示例 3:
输入:queens = [[5,6],[7,7],[2,1],[0,7],[1,6],[5,1],[3,7],[0,3],[4,0],[1,2],[6,3],[5,0],[0,4],[2,2],[1,1],[6,4],[5,4],[0,0],[2,6],[4,5],[5,2],[1,4],[7,5],[2,3],[0,5],[4,2],[1,0],[2,7],[0,1],[4,6],[6,1],[0,6],[4,3],[1,7]], king = [3,4]
输出:[[2,3],[1,4],[1,6],[3,7],[4,3],[5,4],[4,5]]
巧妙题解
::: tip
分析:本题要求找到以国王位置处发散的每一条路径上的第一个皇后。
能攻击到国王的皇后,需要满足:
- 与国王在同一水平,竖直或者斜线方向的的皇后。
- 结果只取每条路径上的第一给皇后。
一种思路是枚举每个皇后,去判断是否满足上述条件。
更加巧妙的做法是,站在国王的视角,计算有哪些皇后能被国王「看到」。
想象成从国王的位置发射八个方向的射线,记录每条射线首次遇到的皇后。
这个思路很简单但是如何实现是一个考验编程能力的事情。
:::
代码 | 二维数组控制方向
js
var queensAttacktheKing = function(queens, king) {
//这里将要以整个棋盘创建二维数组,其中皇后位置为true,初始化时全部置为false;
let isQueen = new Array(8).fill(null).map(()=>new Array(8).fill(false));
for(let [x,y] of queens){
isQueen[x][y] = true;
}
//创建一个记录结果的数组;
let res = [];
//这里表示8个方向,表示以国王为原点,在二维坐标系的八个方向
let direction = [[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1],[0,-1],[1,-1]];
//外循环控制方向,每一个方向遍历到遇到皇后或者结束为止
for(const [dx,dy] of direction){
let x = king[0] + dx;
let y = king[1] + dy;
while(x>=0&&x<8&&y>=0&&y<8){
if(isQueen[x][y]){
//第一次在这个方向上遇到皇后,记录其位置并结束循环
res.push([x,y]);
break;
}
//如果没有到循环结束条件,那么遍历将继续在这个方向上继续下去
x+=dx;
y+=dy;
}
}
return res;
};
代码 | 双层循环控制方向
js
ar queensAttacktheKing = function(queens, king) {
//这里将要以整个棋盘创建二维数组,其中皇后位置为true,初始化时全部置为false;
let isQueen = new Set();
for(let [x,y] of queens) isQueen.add(x*8 + y);//存下的每一个皇后位置都有自己位置独特的值
//创建一个记录结果的数组;
let res = [];
//这里循环八个方向,进行遍历查找
for(let dx = -1;dx <= 1; dx++){
for(let dy = -1;dy <= 1; dy++){
if(dx==0&&dy==0) continue;
let x = king[0] + dx;
let y = king[1] + dy;
while(x>=0&&x<8&&y>=0&&y<8){
let pos = x*8 + y;
if(isQueen.has(pos)){
//第一次在这个方向上遇到皇后,记录其位置并结束循环
res.push([x,y]);
break;
}
//如果没有到循环结束条件,那么遍历将继续在这个方向上继续下去
x+=dx;
y+=dy;
}
}
}
return res;
};