N 皇后问题

51. N-Queens

毫无疑问这是道经典题。

一个比较常规的做法可能是每次向棋盘上新加第i个queen时,检查它是否跟前i-1个有冲突。这样的话其实要产生每个solution就要检查0+1+2+...+n-1 = O(n^2)倍,不是特别efficient。

另一种比较6的做法时,维护三个boolean数组ocp90, ocp45, ocp135,分别记录哪些列,45度对角线和135度对角线已经被占。其中ocp45和ocp135的下标规律是:

| | | / / / \ \ \ O O O O O O O O O | | | / / / / \ \ \ \ O O O O O O O O O | | | / / / / \ \ \ \ O O O O O O O O O | | | / / / \ \ \ 3列 5条45度对角线 5条135度对角线 (n等于3时)

  • 同一条45度对角线上i+j值是一样的,在[0, 1, 2n-2]区间内,所以可以用i+j作为index
  • 同一条135度对角线上i-j的值时一样的,在[-(n-1), -(n-2), ..., -2, -1, 0, 1, 2, ..., n-1]范围内,因此可以用i-j+n-1作为index
class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> res = new ArrayList<>();
        if (n == 0)
            return res;
        boolean[] ocp90 = new boolean[n], ocp45 = new boolean[2*n-1], ocp135 = new boolean[2*n-1];
        char[][] board = new char[n][n];
        for (char[] row : board)
            Arrays.fill(row, '.');
        backtrack(res, board, 0, n, ocp90, ocp45, ocp135);
        return res;
    }

    public void backtrack(List<List<String>> res, char[][] board, int i, int n, boolean[] ocp90, boolean[] ocp45, boolean[] ocp135){
        if (i == n){
            List<String> l = new ArrayList<>();
            for (char[] row : board)
                l.add(new String(row));
            res.add(l);
            return;
        }
        for (int j = 0; j < n; j++){
            if (!ocp90[j] && !ocp45[i+j] && !ocp135[i-j+n-1]){
                ocp90[j] = true;
                ocp45[i+j] = true;
                ocp135[i-j+n-1] = true;
                board[i][j] = 'Q';
                backtrack(res, board, i+1, n, ocp90, ocp45, ocp135);
                board[i][j] = '.';
                ocp135[i-j+n-1] = false;
                ocp45[i+j] = false;
                ocp90[j] = false;
            }
        }
    }
}

52. N-Queens II

和上一道题不同的地方是,这道题要求返回解的个数。

所以做法上的区别就是:找到一个解时,不需要再把board configuration加到一个list里,而是想办法累计解的个数就行了。

那么问题来了:怎么累计解的个数呢?常用的方法有两种:

  1. 直接用一个全局int变量。但是这样感觉看起来比较不好看。。。
  2. dfs返回搜索树中以当前节点为根的子树的解的个数(比较拗口。。。其实就是当前节点的返回值是它几个child节点的返回值的累加和。。。)

这里采用了第二种方法:

class Solution {
    public int totalNQueens(int n) {
        if (n <= 0)
            return 0;
        boolean[] ocp90 = new boolean[n], ocp45 = new boolean[2*n-1], ocp135 = new boolean[2*n-1];
        return dfs(n, 0, ocp90, ocp45, ocp135);
    }

    public int dfs(int n, int i, boolean[] ocp90, boolean[] ocp45, boolean[] ocp135){
        if (i == n)
            return 1;
        int sum = 0;
        for (int j = 0; j < n; j++){
            if (!ocp90[j] && !ocp45[i+j] && !ocp135[i-j+n-1]){
                ocp90[j] = true;
                ocp45[i+j] = true;
                ocp135[i-j+n-1] = true;
                sum += dfs(n, i+1, ocp90, ocp45, ocp135);
                ocp90[j] = false;
                ocp45[i+j] = false;
                ocp135[i-j+n-1] = false;
            }
        }
        return sum;
    }
}

results matching ""

    No results matching ""