51. N 皇后(难度:困难)
题目链接:https://leetcode.cn/problems/n-queens/
题目描述
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
示例 1:
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1
输出:[["Q"]]
提示:
1 <= n <= 9
解法:回溯法
通过题目描述,皇后出现的位置,有四种情况是不允许的:
- 同一行不能有两个皇后
- 同一列不能有两个皇后
- 从左上到右下一条斜线上不能有两个皇后
- 从右上到左下一条斜线上不能有两个皇后
针对这四种不满足的情况,在不超时的情况下完成,只能是在O(1)的时间复杂度下才可以。
如何在O(1)时间复杂度完成呢?
我们通过观察下标,不难发现有一下规律:
- 每一行是否有皇后,我们可以用一个数组来记录。
- 每一列是否有皇后,我们也可以使用一个数组来记录。
- 从左上到右下一条斜线上所有格子坐标(row,col),都会满足(row - col)相等,所以我们也可以使用一数组来记录。
- 从右上到左下一条斜线上所有格子坐标(row,col),都会满足(row + col)相等,所以我们也可以使用一数组来记录。
代码:
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> result = new ArrayList<>();
int[] queues = new int[n];
Arrays.fill(queues,-1);
List<Integer> col = new ArrayList<>();
List<Integer> diag1 = new ArrayList<>();
List<Integer> diag2 = new ArrayList<>();
build(result,n,0,queues,col,diag1,diag2);
return result;
}
private void build(List<List<String>> result, int n, int row, int[] queues, List<Integer> col, List<Integer> diag1, List<Integer> diag2) {
if(row == n) {
List<String> re = buildResult(queues,n);
result.add(re);
} else {
for(int i = 0;i<n;i++) {
if(col.contains(i)) {
continue;
}
int d1 = row - i;
if(diag1.contains(d1)) {
continue;
}
int d2 = row + i;
if(diag2.contains(d2)) {
continue;
}
queues[row] = i;
col.add(i);
diag1.add(d1);
diag2.add(d2);
build(result,n,row+1,queues,col,diag1,diag2);
queues[row] = -1;
col.remove(row);
diag1.remove(row);
diag2.remove(row);
}
}
}
private List<String> buildResult(int[] queues, int n) {
List<String> result = new ArrayList<>();
for(int i = 0;i<queues.length;i++) {
StringBuilder stringBuilder = new StringBuilder();
for(int j = 0;j<n;j++) {
if(j == queues[i]) {
stringBuilder.append("Q");
} else {
stringBuilder.append(".");
}
}
result.add(stringBuilder.toString());
}
return result;
}
}