题目描述
在一个 8x8 的棋盘上,放置着若干「黑皇后」和一个「白国王」。
「黑皇后」在棋盘上的位置分布用整数坐标数组 queens 表示,「白国王」的坐标用数组 king 表示。
「黑皇后」的行棋规定是:横、直、斜都可以走,步数不受限制,但是,不能越子行棋。
请你返回可以直接攻击到「白国王」的所有「黑皇后」的坐标(任意顺序)。
力扣:1222.可以攻击国王的皇后
输入:queens = [ [0 , 0] , [1 , 1] , [2 , 2] , [3 , 4] , [3 , 5] , [4 , 4] , [4 , 5] ] , king = [3 , 3]
输出:[ [2 , 2] , [3 , 4] , [4 , 4] ]
题目分析:
题目意思还是很容易理解的,但可能第一时间会被题目误导,想到 从皇后Q 出发,判断是否能直接攻击到 国王K , 国王嘛 (懂得都懂) ,皇后可能会很多,如果挨个判断不仅耗时还麻烦,逆向思考,会发现 国王能直接攻击的皇后 ,和皇后能直接攻击国王,是等价的问题 ,毕竟国王只有一个。
因此只要考虑 国王在八个方向上能直接攻击到的皇后 问题即可解决。
考虑到皇后是通过一个二维数组来存储坐标,如果每次移动都需要比对二维数组,处理起来相对麻烦,因此可以先将棋盘还原出来,把相应的坐标位置设置为 Q ,那么每次只需要判断格子的内容是否为 Q 即可。
char[][] chess = new char[8][8];
for(int i = 0 ; i < 8 ; i ++)
for(int j = 0 ; j < 8 ; j ++)
chess[i][j] = '.';
for(int[] black : queens)
chess[black[0]][black[1]] = 'Q';
棋盘已经构建完成,但 国王有八个方向需要判断 ,不可能每个方向用一个 for 循环解决 ,方向处理如下:
// 定义 8 个方向
int[] dr = {-1 , 1 , 0 , 0 , -1 , -1 , 1 , 1}; // 上 下 左 右 左上 右上 左下 右下
int[] dc = {0 , 0 , -1 , 1 , -1 , 1 , -1 , 1};
for(int i = 0 ; i < 8 ; i ++){
for(int r = row , c = col ; r >= 0 && r < 8 && c >= 0 && c < 8 ; r += dr[i] , c += dc[i]){
if(chess[r][c] == 'Q'){
result.add(Arrays.asList(r , c));
break;
}
}
}
完整代码:
class Solution {
public List<List<Integer>> queensAttacktheKing(int[][] queens, int[] king) {
// 还原棋盘
char[][] chess = new char[8][8];
for(int i = 0 ; i < 8 ; i ++)
for(int j = 0 ; j < 8 ; j ++)
chess[i][j] = '.';
for(int[] black : queens)
chess[black[0]][black[1]] = 'Q';
List<List<Integer>> result = new ArrayList<>();
solve(result , chess , king[0] , king[1]);
return result;
}
// 只需要对 K 的 8 个方向进行判断,每个方向上第一个遇到的 Q 存入 结果集中
void solve(List<List<Integer>> result , char[][] chess , int row , int col){
// 8 个方向
int[] dr = {-1 , 1 , 0 , 0 , -1 , -1 , 1 , 1}; // 上 下 左 右 左上 右上 左下 右下
int[] dc = {0 , 0 , -1 , 1 , -1 , 1 , -1 , 1};
for(int i = 0 ; i < 8 ; i ++){
for(int r = row , c = col ; r >= 0 && r < 8 && c >= 0 && c < 8 ; r += dr[i] , c += dc[i])
if(chess[r][c] == 'Q'){
result.add(Arrays.asList(r , c));
break;
}
}
}
}