题目
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 **n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例 1:
输入: n = 4
输出: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释: 如上图所示,4 皇后问题存在两个不同的解法。
题解
方式一:暴力
step1:遍历棋盘第一行,确定第一个皇后
step2:按规则更新棋盘,将可攻击的位置禁用
step3:直到皇后数量达到n
方式二:回溯
也可以利用下标计算判断是否能选择当前列
List<List<String>> result = new ArrayList<>();
Set<Integer> cols = new HashSet<>(); // 哪一列有皇后
Set<Integer> set1 = new HashSet<>(); // 向下斜线有皇后 row - col = 固定值
Set<Integer> set2 = new HashSet<>(); // 向上斜线有皇后 row + col = i
public List<List<String>> solveNQueens(int n) {
int[] queens = new int[n]; // 每一行 皇后的下标
Arrays.fill(queens, -1);
backtrack(queens, n, 0);
return result;
}
public void backtrack(int[] queens, int n, int row) {
if (row == n) {
result.add(getBoard(queens, n));
return;
}
// 遍历row行所有列,选择不被攻击的列放皇后
for (int i = 0; i < n; i++) {
if (cols.contains(i)) {
continue;
}
int x = row - i;
if (set1.contains(x)) {
continue;
}
int y = row + i;
if (set2.contains(y)) {
continue;
}
// 三条线都没有皇后,当前列可以选择
queens[row] = i;
cols.add(i); // row 行 i 列 已经存在皇后
set1.add(x); // 行 - 列 差值为x的斜线上已经存在皇后
set2.add(y); // 行 + 列 和为y的斜线上已经存在皇后
backtrack(queens, n, row + 1); // 进入下一行
queens[row] = -1;
cols.remove(i);
set1.remove(x);
set2.remove(y);
}
}
public List<String> getBoard(int[] queens, int n) {
List<String> board = new ArrayList<>();
for (int i = 0; i < n; i++) {
char[] row = new char[n];
Arrays.fill(row, '.');
row[queens[i]] = 'Q'; // 第i行皇后的下标 = queens[i]
board.add(new String(row));
}
return board;
}
总结
算法:回溯