方法 dfs + 回溯
- 使用一个数组记录每行放置的皇后的列下标,依次在每一行放置一个皇后。
- 每次新放置的皇后都不能和已经放置的皇后之间有攻击:即新放置的皇后不能和任何一个已经放置的皇后在同一列以及同一条斜线上,并更新数组中的当前行的皇后列下标。
- 当 N 个皇后都放置完毕,则找到一个可能的解。当找到一个可能的解之后,将数组转换成表示棋盘状态的列表,并将该棋盘状态的列表加入返回列表。
如何表示两个方向的斜线呢?对于每个方向的斜线,需要找到斜线上的每个位置的行下标与列下标之间的关系。
- 方向一的斜线为从左上到右下方向,同一条斜线上的每个位置满足行下标与列下标之差相等
- 方向二的斜线为从右上到左下方向,同一条斜线上的每个位置满足行下标与列下标之和相等
class Solution {
List<List<String>> res = new ArrayList<>();
int[] pos; // queen在每一行的位置index
public List<List<String>> solveNQueens(int n) {
Set<Integer> column = new HashSet<>(); // 不能在这些列放置
Set<Integer> diagonol1 = new HashSet<>(); // 不能在这些对角线放置
Set<Integer> diagonol2 = new HashSet<>(); // 不能在这些对角线放置
pos = new int[n];
dfs(n, 0, column, diagonol1, diagonol2);
return res;
}
public void dfs(int n, int curRow, Set<Integer> column, Set<Integer> diagonol1 ,Set<Integer> diagonol2) {
if (curRow == n) {
res.add(getBoard(pos, n)); // 找到了一个解,生成棋盘
return;
}
for (int i = 0; i < n; i++) {
// 当前列是不能放置queen的,因为会有冲突
if (column.contains(i) || diagonol1.contains(i + curRow) || diagonol2.contains(i - curRow)) {
continue;
}
pos[curRow] = i; // 当前行,queen放置在i为index的列
column.add(i); // 列
diagonol1.add(i + curRow);// 对角线1
diagonol2.add(i - curRow);// 对角线2
dfs(n, curRow + 1, column, diagonol1, diagonol2);
pos[curRow] = -1; // 回溯
column.remove(i);// 列
diagonol1.remove(i + curRow);// 对角线1
diagonol2.remove(i - curRow);// 对角线2
}
}
// 根据皇后在每一row的位置,生成棋盘
public List<String> getBoard(int[] pos, int n) {
List<String> board = new ArrayList<>();
for (int i = 0; i < n; i++) {
String row = "";
int queenPos = pos[i]; // 当前行皇后的位置
for (int j = 0; j < n; j++) {
if (queenPos == j) {
row += "Q";
} else {
row += ".";
}
}
board.add(row); // 加入一行
}
return board;
}
}