问题描述
问题分析
- 大名鼎鼎的 N 皇后问题,要求n个皇后中任意两个元素都不处于同一行,同一列,同一对角线,返回所有的可能性放置结果。
- 既然是返回所有的可能性,那么一定是用 dfs 去搜索所有的结果。以每一行为单位(这样保证同一行没有重复皇后),尝试在该行的每一列上放置皇后,若与该位置处于同一列或者同一对角线已有元素,那么剪枝。否则,继续对下一层进行 dfs。直至dfs到最后一层,收集结果。
那么如何判断同一列,同一对角线没有元素呢?
- 对于同一列,可以用一个
colVisited[n]
数组,colVisited[i] = true
表示第 i 列已有元素。 - 对于对角线而言,需要考虑左右两个方向的对角线,每个方向的对角线都有
2*n-1
条。
对于右上到左下下对角线,处于同一对角线的元素,x,y坐标之和相等,所以,对于该方向对角线,可以用一个长度为2*n - 1
的d1[k] = true
来表示 坐标和为k
的对角线已经有了元素。
对于 左上到右下方向的对角线,处于同一对角线的元素,x,y坐标之差相等,所以,对于该方向的对角线, 如果[x,y] 已有元素,那么d2[i - j + n - 1] = true
, 加 n- 1 是为了保证0索引开始。
- 对于同一列,可以用一个
该实现中还有个小技巧便是,用 pos.get(i) = j ,来表示第 i 行 第 j 列放置了皇后,便于最后生成为二维矩阵.
经验教训
- 如何从一个问题抽象出来,看成一个dfs的问题,dfs如何进行,回溯如何使用,这是一个重点。
代码实现
class Solution {
public List<List<String>> solveNQueens(int n) {
if (n <= 0) {
return new ArrayList<>();
}
List<List<String>> res = new ArrayList<>();
//左对角线
boolean[] d1 = new boolean[2 * n - 1];
//右对角线
boolean[] d2 = new boolean[2 * n - 1];
//该列是否已有皇后
boolean[] colVisited = new boolean[n];
//从第0行开始,逐行放置皇后,列出所有可能性结果
findQueens(n, 0, colVisited, d1, d2, new ArrayList<>(), res);
return res;
}
//在第 row 行 及其之后行放置皇后,pos.get(i) = j ,是标志 第 i 行的皇后放在了第 j列
public void findQueens(int n, int row, boolean[] colVisited, boolean[] d1, boolean[] d2, ArrayList<Integer> pos, List<List<String>> res) {
//所有行都已经添加完毕
if (row == n) {
res.add(generateGrid(pos));
return;
}
//将皇后放在第row行第j列
for (int j = 0; j < n; j++) {
//若当前列或者当前对角线已有皇后,则不能放置
if (colVisited[j] || d1[row + j] || d2[row - j + n - 1]) {
continue;
}
//第row行第j列符合规范
//设置标志
colVisited[j] = true;
d1[row + j] = true;
d2[row - j + n - 1] = true;
pos.add(j);
//dfs
findQueens(n, row + 1, colVisited, d1, d2, pos, res);
//利用回溯,恢复标志
colVisited[j] = false;
d1[row + j] = false;
d2[row - j + n - 1] = false;
//恢复pos
pos.remove(pos.size() - 1);
}
return;
}
//根据 pos来填满整个矩阵: pos.get(i) = j ,是标志 第 i 行的皇后放在了第 j列
public ArrayList<String> generateGrid(ArrayList<Integer> pos) {
ArrayList<String> res = new ArrayList<>();
int n = pos.size();
for (int i = 0; i < n; i++) {
int col = pos.get(i);
StringBuilder sb = new StringBuilder();
for (int k = 0; k < n; k++) {
sb.append(k == col ? 'Q' : '.');
}
res.add(sb.toString());
}
return res;
}
}