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

国王的位置为基准, 每次向周围(八个方向)遍历一遍, 碰到皇后的将其添加到结果, 并删除该方向, 否则则遍历下一周

直到超出棋盘范围或八个方向上的皇后都遇到了

java 黑白皇后问题 黑白皇后棋规则_题解

简单DFS

国王的位置为基准, 每次选出一个方向深度遍历, 直到遇到皇后或超出边界

java 黑白皇后问题 黑白皇后棋规则_算法_02

代码实现

纯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;
                }
            }
        }
    }
}