[leetcode 周赛 158] 1222 可以攻击国王的皇后
1222 Path with Maximum Gold 可以攻击国王的皇后
问题描述
在一个 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]]
- 提示:
1 <= queens.length <= 63
queens[0].length == 2
0 <= queens[i][j] < 8
king.length == 2
0 <= king[0], king[1] < 8
- 一个棋盘格上最多只能放置一枚棋子。
思路
- 读题
选取在国王
的横/竖/斜角八个方向上的最近皇后
的位置
简单BFS
以国王
的位置为基准, 每次向周围(八个方向)遍历一遍, 碰到皇后
的将其添加到结果, 并删除该方向, 否则则遍历下一周
直到超出棋盘范围或八个方向上的皇后
都遇到了
简单DFS
以国王
的位置为基准, 每次选出一个方向深度遍历, 直到遇到皇后
或超出边界
代码实现
纯BFS
class Solution {
/**
* DN
* 八个方向 棋盘宽度/高度
*/
private final static int DN = 8;
/**
* 八个方向
* 上下左右 左上 左下 右上 右下
*/
private static int[][] direct = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
/**
* isFind
* 确认该方向是否寻找到结果或寻找完
* 默认初始化为FALSE
*/
private boolean[] isFind = new boolean[DN];
/**
* 国王的位置 (kx, ky)
*/
private int kx, ky;
public List<List<Integer>> queensAttacktheKing(int[][] queens, int[] king) {
int[][] area = new int[DN][DN];
// 初始化棋盘 在棋盘上'落子'
for (int[] queen : queens) {
int x = queen[0], y = queen[1];
area[x][y] = 1;
}
List<List<Integer>> res = new LinkedList<>();
kx = king[0];
ky = king[1];
bfs(area, res, 1);
return res;
}
/**
* 以(kx, ky)为基准点, 八个方向广度遍历第layer环
* @param area 活动范围 棋盘 8*8
* @param res 查询结果
* @param layer 环数
*/
private void bfs(int[][] area, List<List<Integer>> res, int layer) {
// 判断是否所有方向都搜索完
boolean isContinue = hasDirect(isFind);
if (!isContinue) {
return;
}
for (int i = 0; i < direct.length; i++) {
// 如果该方向没有找完 isFind[i]==false
if (!isFind[i]) {
// 该方向搜索的下一个位置
int nx = kx + layer * direct[i][0], ny = ky + layer * direct[i][1];
// 如果搜索的位置还在棋盘范围内 则该方向还可以继续搜索
if (0 <= nx && nx < 8 && 0 <= ny && ny < 8) {
// 该方向遇到'皇后' 该方向'功成身退'
if (area[nx][ny] > 0) {
isFind[i] = true;
// 添加所遇到的'皇后'位置
List<Integer> cur = new LinkedList<>();
cur.add(nx);
cur.add(ny);
res.add(cur);
}
// 该方向搜索位置超出范围 该方向放弃
} else {
isFind[i] = true;
}
}
}
// 第layer层搜索完毕 前往下一层
bfs(area, res, layer + 1);
}
/**
* 判断布尔数组中是否还有FALSE值
* @param booleans 被判断布尔数组
* @return true 数组中还有FALSE值
*/
private boolean hasDirect(boolean[] booleans) {
for (boolean b : booleans) {
if (!b) {
return true;
}
}
return false;
}
}
DFS
class Solution {
/**
* DN
* 八个方向 棋盘宽度/高度
*/
private final static int DN = 8;
/**
* 八个方向
* 上下左右 左上 左下 右上 右下
*/
private static int[][] direct = {{0, 1}, {0, -1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
/**
* 国王的位置 (kx, ky)
*/
private int kx, ky;
public List<List<Integer>> queensAttacktheKing(int[][] queens, int[] king) {
int[][] area = new int[DN][DN];
// 初始化棋盘 在棋盘上'落子'
for (int[] queen : queens) {
int x = queen[0], y = queen[1];
area[x][y] = 1;
}
List<List<Integer>> res = new LinkedList<>();
kx = king[0];
ky = king[1];
dfs(area, res);
return res;
}
/**
* 以国王的位置(kx, ky)为基准, 分别深度遍历八个方向
* @param area 棋盘 活动范围
* @param res 查询结果
*/
private void dfs(int[][] area, List<List<Integer>> res) {
for (int i = 0; i < DN; i++) {
// 死磕一个方向 直到遇到'皇后'或撞墙
for (int j = 1; j < DN; j++) {
int nx = kx + direct[i][0] * j, ny = ky + direct[i][1] * j;
if (0 <= nx && nx < DN && 0 <= ny && ny < DN) {
if (area[nx][ny] > 0) {
List<Integer> list = new LinkedList<>();
list.add(nx);
list.add(ny);
res.add(list);
break;
}
// '撞墙'就放弃该方向
} else {
break;
}
}
}
}
}