n 皇后问题 研究的是如何将n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的n 皇后
问题 的解决方案。
每一种解法包含一个不同的n
皇后问题 的棋子放置方案,该方案中'Q'
和'.'
分别代表了皇后和空位。
【示例-1】
输入:n = 4
输出:[[".Q…","…Q",“Q…”,"…Q."],["…Q.",“Q…”,"…Q",".Q…"]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
示例-2
输入:n = 1
输出:[[“Q”]]
解题思想:
此题,采用回溯法思想求解:
为了判断在当前列和斜线上是否有皇后,定义三个集合,columns
, dias1
,dias2
判断当前列,两条斜线上是否已经有了皇后。
columns的做法很好判断, 使用列的下标就可以代表一个单独的列。
而对于两条斜线,需要分开考虑,观察是否能代表。
这里,我定义dias1
为右斜线,并将 row + i
作为唯一的标识。可以唯一的标识一个斜线,将其放入set集合中,就可以判断,当前斜线上是否有皇后。
左上斜也是一样。
[code]
public List<List<String>> solveNQueens(int n) {
List<List<String>> solutions = new ArrayList<>();
// 定义索引下标为行 , 值为列
int[] queue = new int[n];
Arrays.fill(queue, -1); // 填充
// 存放行和列和每一条斜线所存放的值
Set<Integer> columns = new HashSet<>();
// 记录每右下条斜线是否放值
Set<Integer> dias1 = new HashSet<>();
// 记录每左上斜是否放值
Set<Integer> dias2 = new HashSet<>();
// 回溯
backtracking(solutions, queue, n, 0, columns, dias1, dias2);
return solutions;
}
private void backtracking(List<List<String>> solutions, int[] queue, int n, int row, Set<Integer> columns, Set<Integer> dias1, Set<Integer> dias2) {
if(row == n){
// 生成结果
List<String> tmp = generate(queue, n);
solutions.add(tmp);
} else{
// 开始尝试在n列中放置
for(int i = 0; i < n; i ++){
// 判断当前填 (row , i )是否符合条件 , columns 代表当前一列中是否有, dias1,dias2 判断当前斜线是否有 ,
if(columns.contains(i) || dias1.contains(row - i) || dias2.contains(row + i) ) continue;
queue[row] = i;
// 将所有的值进行记录
columns.add(i);
dias1.add(row - i);
dias2.add(row + i);
backtracking(solutions, queue, n, row + 1, columns, dias1, dias2);
// 回溯后续操作
columns.remove(i);
dias1.remove(row - i);
dias2.remove(row + i);
}
}
}
private List<String> generate(int[] queue, int n) {
List<String> res = new ArrayList<>();
for(int i = 0; i < n; i++){
char[] row = new char[n];
Arrays.fill(row, '.');
row[queue[i]] = 'Q';
res.add(new String(row));
}
return res;
}
}