N 皇后问题:将 n
个皇后放置在 n x n
的棋盘上,使得皇后彼此之间不能相互攻击(即任何两个皇后不能在同一行、同一列或同一斜线上)。
返回所有不同的解决方案。每个解决方案包含一个明确的 n x n
的棋盘布局,其中 'Q'
表示皇后,'.'
表示空位。
输入:
n = 4
输出:
[
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释:
输入:
n = 1
输出:
[["Q"]]
解释:
我们需要在 n x n
的棋盘上放置 n
个皇后,使得它们互不攻击。皇后可以攻击同一行、同一列或同一斜线上的其他皇后。
ca[j]
表示第 j
列是否被占用。cb[i + j]
表示左斜线是否被占用。cc[n - 1 - (i - j)]
表示右斜线是否被占用。n
个皇后,则将当前棋盘布局加入结果列表。class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> ans = new ArrayList<>();
boolean[] ca = new boolean[n];
boolean[] cb = new boolean[2 * n - 1];
boolean[] cc = new boolean[2 * n - 1];
char[][] table = new char[n][n];
for (int i = 0; i < n; i++) {
Arrays.fill(table[i], '.');
}
dfs(0, n, table, ca, cb, cc, ans);
return ans;
}
static void dfs(int i, int n, char[][] table,
boolean[] ca,
boolean[] cb,
boolean[] cc,
List<List<String>> ans) {
if (i == n) {
List<String> solution = new ArrayList<>();
for (char[] chars : table) {
solution.add(new String(chars));
}
ans.add(solution);
return;
}
for (int j = 0; j < n; j++) {
if (ca[j] || cb[i + j] || cc[n - 1 - (i - j)]) {
continue;
}
table[i][j] = 'Q';
ca[j] = cb[i + j] = cc[n - 1 - (i - j)] = true;
dfs(i + 1, n, table, ca, cb, cc, ans);
table[i][j] = '.';
ca[j] = cb[i + j] = cc[n - 1 - (i - j)] = false; }
}
}
List<List<String>> ans = new ArrayList<>();
ans
用于存储所有合法的棋盘布局。boolean[] ca = new boolean[n]; // 列冲突
boolean[] cb = new boolean[2 * n - 1]; // 左斜线冲突
boolean[] cc = new boolean[2 * n - 1]; // 右斜线冲突
ca
记录每一列是否被占用。cb
记录每一条左斜线是否被占用。cc
记录每一条右斜线是否被占用。char[][] table = new char[n][n];
for (int i = 0; i < n; i++) {
Arrays.fill(table[i], '.'); // 初始化棋盘
}
table
表示棋盘,初始化为 '.'
。dfs(0, n, table, ca, cb, cc, ans);
static void dfs(int i, int n, char[][] table,
boolean[] ca,
boolean[] cb,
boolean[] cc,
List<List<String>> ans) {
if (i == n) {
List<String> solution = new ArrayList<>();
for (char[] chars : table) {
solution.add(new String(chars));
}
ans.add(solution);
return;
}
n
个皇后,则将当前棋盘布局加入结果列表。for (int j = 0; j < n; j++) {
i
行的每一列尝试放置皇后。if (ca[j] || cb[i + j] || cc[n - 1 - (i - j)]) {
continue;
}
table[i][j] = 'Q';
ca[j] = cb[i + j] = cc[n - 1 - (i - j)] = true;
dfs(i + 1, n, table, ca, cb, cc, ans);
table[i][j] = '.';
ca[j] = cb[i + j] = cc[n - 1 - (i - j)] = false;
n
,因此额外空间复杂度为 O(n)。'Q'
和 '.'
分别表示皇后和空位。class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> ans = new ArrayList<>(); // 结果列表
boolean[] ca = new boolean[n]; // 列冲突
boolean[] cb = new boolean[2 * n - 1]; // 左斜线冲突
boolean[] cc = new boolean[2 * n - 1]; // 右斜线冲突
char[][] table = new char[n][n]; // 棋盘
for (int i = 0; i < n; i++) {
Arrays.fill(table[i], '.'); // 初始化棋盘
}
dfs(0, n, table, ca, cb, cc, ans); // DFS
return ans;
}
static void dfs(int i, int n, char[][] table,
boolean[] ca,
boolean[] cb,
boolean[] cc,
List<List<String>> ans) {
if (i == n) { // 找到一个解
List<String> solution = new ArrayList<>();
for (char[] chars : table) {
solution.add(new String(chars)); // 将棋盘布局加入解
}
ans.add(solution); // 将解加入结果列表
return;
}
for (int j = 0; j < n; j++) { // 尝试在第 i 行的每一列放置皇后
if (ca[j] || cb[i + j] || cc[n - 1 - (i - j)]) { // 冲突检测
continue;
}
table[i][j] = 'Q'; // 放置皇后
ca[j] = cb[i + j] = cc[n - 1 - (i - j)] = true; // 标记冲突
dfs(i + 1, n, table, ca, cb, cc, ans); // 递归
table[i][j] = '.'; // 回溯
ca[j] = cb[i + j] = cc[n - 1 - (i - j)] = false; // 撤销冲突标记
}
}
}
通过回溯算法和冲突检测,能够高效地解决 N 皇后问题。