51. n 皇后


官方链接

https://leetcode-cn.com/problems/n-queens/

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

上图为 8 皇后问题的一种解法。

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

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

示例:

输入: 4 输出: [ [".Q..", // 解法 1 "...Q", "Q...", "..Q."],

["..Q.", // 解法 2 "Q...", "...Q", ".Q.."] ] 解释: 4 皇后问题存在两个不同的解法。

思路

用四皇后来验证

解法一

回溯

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
      if n < 1:
        return []

      self.result = []
      self.cols = set()
      self.pie = set()
      self.na = set()
      self.dfs(n, 0, [])
      return self._generate_result(n)

    def dfs(self, n, row, cur_state):
      # terminator
      if row >= n:
        self.result.append(cur_state)
        return

      # process
      for col in range(n):
        if col in self.cols or row + col in self.pie or row - col in self.na:
          continue

        self.cols.add(col)
        self.pie.add(row + col)
        self.na.add(row - col)

        self.dfs(n, row + 1, cur_state + [col])

        self.cols.remove(col)
        self.pie.remove(row + col)
        self.na.remove(row - col)

    def _generate_result(self, n):
      board = []
      for res in self.result:
        for i in res:
          board.append('.' * i + 'Q' + '.' * (n - i - 1))

      return [board[i: i + n] for i in range(0, len(board), n)]
class Solution {

    public Set<Integer> cols = new HashSet<>();
    public Set<Integer> pie = new HashSet<>();
    public Set<Integer> na = new HashSet<>();
    public List<List<Integer>> result = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {

        dfs(n, 0, new ArrayList<>());
        return generateResult(n);        
    }

    private void dfs(int n, int row, List<Integer> list) {
        if (row >= n) {
            result.add(new ArrayList<>(list));
            return;
        }

        for (int col = 0; col < n; col++) {
            if (cols.contains(col) || pie.contains(row + col) || na.contains(row - col)) continue;

            cols.add(col);
            pie.add(row + col);
            na.add(row - col);

            list.add(col);

            dfs(n, row + 1, list);

            cols.remove(col);
            pie.remove(row + col);
            na.remove(row - col);

            list.remove(list.size() - 1);
        }
    }

    private List<List<String>> generateResult(int n) {

        List<List<String>> ret = new ArrayList<>();

        for (List<Integer> res: result) {
            List<String> list = new ArrayList<>();
            for (Integer col: res) {
                char[] chars = new char[n];
                Arrays.fill(chars, '.');
                chars[col] = 'Q';
                list.add(String.valueOf(chars));
            }
            ret.add(list);
        }
        return ret;
    }
}
class Solution {

    public List<List<String>> solveNQueens(int n) {

        List<List<String>> res = new ArrayList<>();
        helper(res, n, 0, new boolean[n], new boolean[2*n], new boolean[2*n], new ArrayList<>());
        return res;
    }

    private void helper(List<List<String>> res, int n, int row, boolean[] cols, boolean[] pie, boolean[] na, List<String> board) {
        if (row == n) {
            res.add(new ArrayList<>(board));
            return;
        }

        for (int col = 0; col < n; col++) {

            int id1 = row - col + n;
            int id2 = 2*n - row - col - 1;

            if (cols[col] || pie[id1] || na[id2]) continue;

            char[] r = new char[n];
            Arrays.fill(r, '.');
            r[col] = 'Q';

            board.add(row, String.valueOf(r));

            cols[col] = true;
            pie[id1] = true;
            na[id2] = true;

            helper(res, n, row + 1, cols, pie, na, board);

            cols[col]  = false;
            pie[id1] = false;
            na[id2] = false;

            board.remove(board.size() - 1);
        }
    }
}

简洁的解法

class Solution:
    # 附带非位运算判重(Python)
    def solveNQueens(self, n: int) -> List[List[str]]:
      self.result = []
      self.dfs(n, [], [], [])
      return [ ['.' * i + 'Q' + '.' * (n-i-1) for i in sol] for sol in self.result]

    def dfs(self, n, queens, xy_diff, xy_sum):
      length = len(queens)
      if length == n:
        self.result.append(queens)
        return

      for col in range(n): # col 是列
        if col not in queens and length - col not in xy_diff and length + col not in xy_sum:
          self.dfs(n, queens + [col], xy_diff + [length - col], xy_sum + [length + col])

其它解法

C++ 题解

class Solution {
public:
    std::vector<std::vector<std::string> > solveNQueens(int n) {
        std::vector<std::vector<std::string> > res;
        std::vector<std::string> nQueens(n, std::string(n, '.'));
        solveNQueens(res, nQueens, 0, n);
        return res;
    }
private:
    void solveNQueens(std::vector<std::vector<std::string> > &res, std::vector<std::string> &nQueens, int row, int &n) {
        if (row == n) {
            res.push_back(nQueens);
            return;
        }
        for (int col = 0; col != n; ++col)
            if (isValid(nQueens, row, col, n)) {
                nQueens[row][col] = 'Q';
                solveNQueens(res, nQueens, row + 1, n);
                nQueens[row][col] = '.';
            }
    }

    // 这里傻算不如直接用数组存储
    bool isValid(std::vector<std::string> &nQueens, int row, int col, int &n) {
        //check if the column had a queen before.
        for (int i = 0; i != row; ++i)
            if (nQueens[i][col] == 'Q')
                return false;
        //check if the 45° diagonal had a queen before.
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; --i, --j)
            if (nQueens[i][j] == 'Q')
                return false;
        //check if the 135° diagonal had a queen before.
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; --i, ++j)
            if (nQueens[i][j] == 'Q')
                return false;
        return true;
    }
};