N 皇后 |刷题打卡

682 阅读3分钟

掘金团队号上线,助你 Offer 临门! 点击 查看大厂春招职位

一、题目描述:

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

image.png

示例 1:

输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1
输出:[["Q"]]

题目地址:leetcode-cn.com/problems/n-…

二、思路分析:

非常经典的递归+回溯算法题目。每次递归时放置一个皇后,当前条件判断结束后需要回溯到上一个状态。然后把放置好的皇后放到下一个可以放置的位置。

按行去递归,每一次递归,就尝试在某一行放置一个皇后。直到当前行无法再放皇后,回溯到上一行。继续尝试。比较耗时的地方是在判断当前位置是否可以放置皇后。可以直接暴力判断,循环整个棋盘,一定能知道是否冲突,优化点的做法是循环所有行。也能判断出来。这里说一下,利用空间换时间的做法,可以不通过循环直接判断出是否可以放置皇后。

需要初始化 4个数组

xFlag[i] = true: 代表 第 i 行已经放置了皇后。
yFlag[i] = true: 代表 第 i 列已经放置了皇后。
mdFlag[i] = true: 代表 第 i 条主对角线已经放置了皇后。
sdFlag[i] = true: 代表 第 i 条次对角线已经放置了皇后。

主对角线(mdFlag):

1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 6 8 9

如果 mdFlag[4] = true,那么说明: 在值为 4 的某个位置已经放置了皇后。


次对角线(sdFlag):

5 4 3 2 1
6 5 4 3 2
7 6 5 4 3
8 7 6 5 4
9 8 7 6 5


如果 mdFlag[6] = true,那么说明: 在值为 6 的某个位置已经放置了皇后。


我们不需要知道已经放置皇后的具体位置,只需要知道,在当前行,当前列,当前
对角线上是否有皇后。


对应关系:

如果在 (i,j) 的位置放置了皇后。那么需要更新 这四个数组

xFlag[i] = true

yFlag[j] = true

mdFlag[i+j] = true

sdFlag[i+n-j-1] =true 


PS:其实我们是按行来递归的,所以可以不用 xFlag 数组的

三、AC 代码:

   public static List<List<String>> solveNQueens(int n) {
        //行
        boolean[] xFlag = new boolean[n];
        //列
        boolean[] yFlag = new boolean[n];
        //主对角线,左上至右下
        boolean[] mdFlag = new boolean[2 * n - 1];
        //次对角线,右上至左下
        boolean[] sdFlag = new boolean[2 * n - 1];

        char[][] checkerboard = new char[n][n];
        List<List<String>> ansList = new ArrayList<>();

        Arrays.fill(xFlag, false);
        Arrays.fill(yFlag, false);
        Arrays.fill(mdFlag, false);
        Arrays.fill(sdFlag, false);

        //初始化棋盘
        for (char[] item : checkerboard) {
            Arrays.fill(item, '.');
        }

        setQueens(checkerboard, xFlag, yFlag, mdFlag, sdFlag, 0, n, ansList);
        return ansList;
    }

    private static void setQueens(char[][] checkerboard, boolean[] xFlag, boolean[] yFlag, boolean[] mdFlag, boolean[]
            sdFlag, int x, int n, List<List<String>> ansList) {

        if (x == n) {
            List<String> ansItem = new ArrayList<>();
            for (char[] item : checkerboard) {
                ansItem.add(new String(item));
            }
            ansList.add(ansItem);
            return;
        }
        for (int i = 0; i < n; i++) {
            if (xFlag[x]) {
                return;
            }
            if (yFlag[i]) {
                continue;
            }
            if (mdFlag[x + i]) {
                continue;
            }
            if (sdFlag[x + n - i - 1]) {
                continue;
            }
            checkerboard[x][i] = 'Q';
            xFlag[x] = true;
            yFlag[i] = true;
            mdFlag[x + i] = true;
            sdFlag[x + n - i - 1] = true;
            setQueens(checkerboard, xFlag, yFlag, mdFlag, sdFlag, x + 1, n, ansList);
            xFlag[x] = false;
            yFlag[i] = false;
            mdFlag[x + i] = false;
            sdFlag[x + n - i - 1] = false;
            checkerboard[x][i] = '.';
        }
    }

四、总结

不得不吐槽下,对于数组来说,python太友好了,同样的思路,python能比 java 少一半代码。