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

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

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

 

示例 1:

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

示例 2:

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

 

提示:

  • 1 <= n <= 9
  • 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
Related Topics
  • 数组
  • 回溯算法
  • \n
  • 👍 914
  • 👎 0
  • 题解

    里面加了个printMap方法,可以看到每一步执行的情况。

    大概的输出情况如下

    
    			o	o	o	o
    			o	o	o	o
    			o	o	o	o
    			o	o	o	o
    			-0--------------------
    			Q	.	.	.
    			.	.	o	o
    			.	o	.	o
    			.	o	o	.
    			-1--------------------
    			Q	.	.	.
    			.	.	Q	.
    			.	.	.	.
    			.	o	.	.
    			-2--------------------
    			Q	.	.	.
    			.	.	.	Q
    			.	o	.	.
    			.	.	o	.
    			-2--------------------
    			Q	.	.	.
    			.	.	.	Q
    			.	Q	.	.
    			.	.	.	.

    根据题意,和皇后棋的特性,米字型方向,长度无限的走法。那么我们可以得出一个初步的结论,要想在NxN的棋盘上放满N个皇后,那必然满足的条件是在每一行上有且只有一个皇后,在每一列上也是有且只有一个皇后。

    按照这个思路我们就在棋盘上,从左上角,第一个格子开始排起,分别求出下一行可能的情况,如果下一行上摆放不了任何一个皇后棋子,那说明这个摆放方法是不可行的,就必须回退上一步,尝试另一种摆放方法。并按照这个规则,直至最后一行也能放下一颗皇后棋子,则说明这种摆放方法是可行的。

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        public List<List<String>> solveNQueens(int n) {
            char[][] availableMap = new char[n][n];
            for (int i = 0; i < n; i++) {
                char[] a = new char[n];
                //设为空 empty
                Arrays.fill(a,'o');
                availableMap[i] = a;
            }
            List<List<String>> res = new ArrayList<>();
            resolve(res,availableMap,0);
    //        System.out.println(res);
            return res;
        }
    
    //    private void printMap(char[][] originMap, int row){
    //        return;
    ////        for (char[] chars : originMap) {
    ////            StringBuilder str = new StringBuilder();
    ////            for (char aChar : chars) {
    ////                str.append("\t\t").append(aChar);
    ////            }
    ////            System.out.println(str);
    ////        }
    ////        System.out.println("-"+row+"--------------------");
    ////        System.out.println("");
    //    }
    
    
        private void resolve(List<List<String>> res,char[][] originMap,int row){
            // 根据特征,我们以第一行的情况开始,每一行必定有一个,且一定只有一个,
            // 不能满足这种情况的摆放方法,必然不能满足这种条件
            int n = originMap.length;
    //        printMap(originMap,row);
            for (int x = 0; x < n; x++){
                boolean rowInsertQ = false;
                //每一行,每一列的不同选择都会派生出不同的分支
                char[][] map = cloneCharArr(originMap);
                for (int i = 0; i < n; i++) {
                    if ( map[row][i] != 'o'){
                        continue;
                    }
                    if (i==x){
                        map[row][i] = 'Q';
                        rowInsertQ = true;
                        //那么对应的所有行上的第i列,和对应行上的斜线坐标格子 都是不可用状态,
                        for (int j = row+1; j < n; j++) {
                            map[j][i] = '.';
                            int left = i-(j-row);
                            int right = i+(j-row);
                            if (left >= 0 && map[j][left]=='o'){
                                map[j][left] = '.';
                            }
                            if (right <n && map[j][right]=='o'){
                                map[j][right] = '.';
                            }
                        }
                    }else{
                        map[row][i] = '.';
                    }
                }
                if (!rowInsertQ){
                    //这行不能插入新皇后,可以提前终止了
                    continue;
                }
                //有插入了新的皇后,可以向下一行探测,如果没有下一行则表示当前行已经是最后一行,那边添加进res中
                if (row<n-1){
                    resolve(res,map,row+1);
                }else{
                    toResult(res,map);
                }
            }
        }
    
        private char[][] cloneCharArr(char[][] map){
            char[][] temp = new char[map.length][map[0].length];
            for (int i = 0; i < map.length; i++) {
                System.arraycopy(map[i], 0, temp[i], 0, map[0].length);
            }
            return temp;
        }
    
        private void toResult(List<List<String>> res, char[][]arr){
            List<String> stringList = new ArrayList<>();
            for (char[] chars : arr) {
                stringList.add(new String(chars));
            }
            res.add(stringList);
        }
    }
    //leetcode submit region end(Prohibit modification and deletion)

    补充个回溯

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
    public List<List<String>> solveNQueens(int n) {
    char[][] chess = new char[n][n];
    for (char[] chars : chess) {
    Arrays.fill(chars, '.');
    }
    List<List<String>> res = new ArrayList<>();
    solve(chess, res, 0);
    return res;
    }

    private void solve(char[][] chess, List<List<String>> res, int row) {
    if (row == chess.length) {
    res.add(construct(chess));
    return;
    }
    //从第⼀⾏开始找
    for (int col = 0; col < chess.length; col++) {
    //判断当前位置是否能放置皇后
    if (valid(chess, row, col)) {
    chess[row][col] = 'Q';
    solve(chess, res, row + 1);
    chess[row][col] = '.';
    }
    }
    }

    //判断当前位置是否能放置皇后
    private boolean valid(char[][] chess, int row, int col) {
    //通俗⼀点就是判断当前坐标位置的上⾯有没有皇后
    for (int i = 0; i < row; i++) {
    if (chess[i][col] == 'Q') return false;
    }
    //判断当前坐标的右上⾓有没有皇后
    for (int i = row - 1, j = col + 1; i >= 0 && j < chess[i].length; i--, j++) {
    if (chess[i][j] == 'Q') return false;
    }
    //判断当前坐标的左上⾓有没有皇后
    for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
    if (chess[i][j] == 'Q') return false;
    }
    return true;
    }

    // 数组转集合
    private List<String> construct(char[][] chess) {
    List<String> path = new ArrayList<>();
    for (char[] chars : chess) {
    path.add(new String(chars));
    }
    return path;
    }
    }