题目描述
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n,返回所有不同的 n 皇后问题 的解决方案。 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ’.’ 分别代表了皇后和空位。
示例 1:

输入:n = 4
输出:[[".Q..","…Q","Q…","..Q."],["..Q.","Q…","…Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1
输出:[["Q"]]
思路&js代码
1、回溯
问:本题和 46. 全排列 的关系是什么? 答:由于每行恰好放一个皇后,记录每行的皇后放在哪一列,可以得到一个 [0,n−1] 的排列 queens。示例 1 的两个图,分别对应排列 [1,3,0,2] 和 [2,0,3,1]。所以我们本质上是在枚举列号的全排列。
问:如何 O(1) 判断两个皇后互相攻击? 答:由于我们保证了每行每列恰好放一个皇后,所以只需检查斜方向。对于 ↗ 方向的格子,行号加列号是不变的。对于 ↖ 方向的格子,行号减列号是不变的。如果两个皇后,行号加列号相同,或者行号减列号相同,那么这两个皇后互相攻击。
问:如何 O(1) 判断当前位置被之前放置的某个皇后攻击到? 答:额外用两个数组 diag1和 diag2分别标记之前放置的皇后的行号加列号,以及行号减列号。如果当前位置的行号加列号在 diag1中(标记为 true),或者当前位置的行号减列号在 diag2中(标记为 true),那么当前位置被之前放置的皇后攻击到,不能放皇后。
var solveNQueens = function(n) {
const ans = [];
const queens = Array(n).fill(0); // 皇后放在 (r,queens[r])
const col = Array(n).fill(false);
const diag1 = Array(n * 2 - 1).fill(false);
const diag2 = Array(n * 2 - 1).fill(false);
function dfs(r) {
if (r === n) {
ans.push(queens.map(c => '.'.repeat(c) + 'Q' + '.'.repeat(n - 1 - c)));
return;
}
// 在 (r,c) 放皇后
for (let c = 0; c < n; c++) {
const rc = r - c + n - 1;
if (!col[c] && !diag1[r + c] && !diag2[rc]) { // 判断能否放皇后
queens[r] = c; // 直接覆盖,无需恢复现场
col[c] = diag1[r + c] = diag2[rc] = true; // 皇后占用了 c 列和两条斜线
dfs(r + 1);
col[c] = diag1[r + c] = diag2[rc] = false; // 恢复现场
}
}
}
dfs(0);
return ans;
};