LeetCode51. N-Queens N皇后问题

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

八皇后

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

N皇后问题是一个经典的算法问题,求N×N的国际象棋棋盘上能摆放多少个皇后,且她们之间不相互攻击,要输出所有可能的摆法。皇后的攻击范围是同一行、同一列以及同在两条45°斜线上的棋子。

解本题的关键是选择一个合适的数据结构来记录放皇后的位置,还要方便检验各个位置是否冲突。使用x和y坐标来记录位置是最直接的,然而保存两个数要用额外的数据结构才行(特殊情况可以用一个int打包),记录下来后判断位置是否冲突也比较麻烦。

经过思考,使用一个int[N]数组来保存皇后的位置是最合适的。数组下标代表y坐标,数组中的数0~N-1代表x坐标。这样保证y坐标不会重复(不会在同一行),判断x坐标是否重复只要遍历数组看是否有重复数字,判断是否在同一斜线也很方便:假设当前位置是int[yi]=xi,从当前位置向前移动,判断 (int[yi-1]==xi+1 || int[yi-1]==xi-1), (int[yi-12]==xi+2 || int[yi-2]==xi-2)...即可。

解决了数据结构和位置检查的问题,剩下的算法就很简单:从位置0开始,检查当前位置能放0~N-1中的哪个数,如果能放且是最后一个数,就把数组转换一下输出,如果没到最后一个数,就对下一个位置递归计算。

代码如下,本算法击败了98%的java算法。

    public static List<List<String>> solveNQueens(int n) {
        List<List<String>> res = new ArrayList<>();
        int[] a = new int[n];
        solveNQueens(res, a, 0);
        return res;
    }

    public static void solveNQueens(List<List<String>> res, int[] a, int pos) {
        int n = a.length;
        for(int j = 0; j < n; j++) {
            if(check(a, pos, j)) {
                a[pos] = j;
                if(pos == n - 1) { // save
                    char[][] board = new char[n][n];
                    for(char[] b : board) {
                        Arrays.fill(b, '.');
                    }
                    List<String> list = new ArrayList<>();
                    for(int i = 0; i < n; i++) {
                        board[i][a[i]] = 'Q';
                        list.add(new String(board[i]));
                    }
                    res.add(list);
                } else solveNQueens(res, a, pos + 1);
            }
        }
    }

    public static boolean check(int[] a, int pos, int j) {
        for(int k = pos - 1; k >= 0; k--) {
            if(a[k] == j) return false;
        }
        for(int k = pos - 1; k >= 0; k--) {
            int diff = pos - k;
            if(a[k] == j + diff || a[k] == j - diff) return false;
        }
        return true;
    }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 回溯算法 回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并...
    fredal阅读 13,728评论 0 89
  • 贪心算法 贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上...
    fredal阅读 9,279评论 3 52
  • 原文地址:http://theory.stanford.edu/~amitp/GameProgramming/ 1...
    达微阅读 19,610评论 0 28
  • 走上工作岗位十五年,参加的培训大大小小的不算多,却也不少。最长的一次培训也只有一周,培训方式往往是以面授形...
    陕县2930孙敏阅读 75评论 0 0
  • 夜深人静一棵树在长在风中它晃动着,同时也在长它动一下长一点再动一下又长一点 在一棵树的体内藏满了那些生长的细胞如同...
    王春涞阅读 157评论 7 5