题目
n
皇后问题研究的是如何将 n
个皇后放置在 n × n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回 n
皇后问题 不同的解决方案的数量。
示例 1:
输入:n = 4 输出:2 解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1 输出:1
解题思路:回溯
为判断一个位置所在的列和两条斜线上是否已有皇后,使用三个集合 、
、
分别记录每一列以及两个方向的每条斜线上是否有皇后。
列的表示法很直观,一共有 列,使用列的下标即可明确表示每一列。
如何表示两个方向的斜线呢?
对于每个方向的斜线,需要找到斜线上的每个位置的行下标与列下标之间的关系。
- 斜线为从左上到右下方向,同一条斜线上的每个位置满足行下标与列下标之差相等
- 斜线为从右上到左下方向,同一条斜线上的每个位置满足行下标与列下标之和相等
每次放置皇后时,对于每个位置判断其是否在三个集合中,如果三个集合都不包含当前位置,则当前位置是可以放置皇后的位置。
复杂度分析
时间复杂度: ,其中
是皇后数量。
空间复杂度: ,其中
是皇后数量。
- 递归调用层数不会超过  ,每个集合的元素个数都不会超过  。
我的代码
public class Solution {
public int DFS(int n,int CurRows,HashSet<Integer> columns,
HashSet<Integer> diagonals1,HashSet<Integer> diagonals2){
// 递归到达最底层
if(CurRows==n){
return 1;
}
int ReturnCount=0;
// 当前CurRows行循环n列
for(int i=0;i<n;i++){
// 检查当前列是否被其他皇后占领
if(columns.contains(i)) continue;
int diagonals1Num = i-CurRows; // 计算右斜号
// 检查当前右斜是否被其他皇后占领
if(diagonals1.contains(diagonals1Num)) continue;
int diagonals2Num = i+CurRows; // 计算左斜号
if(diagonals2.contains(diagonals2Num)) continue;
// 如果此时还没有被 continue 说明此位置可以将其占领
columns.add(i); // 占领当前列
diagonals1.add(diagonals1Num); // 占领右斜
diagonals2.add(diagonals2Num); // 占领左斜
// 递归下一行进行计算
ReturnCount+=DFS(n,CurRows+1,columns,diagonals1,diagonals2);
// 将当前占领的列,左右斜资源释放
columns.remove(i);
diagonals1.remove(diagonals1Num);
diagonals2.remove(diagonals2Num);
// 开始循环尝试占领当前行的下一列
}
return ReturnCount;
}
public int Nqueen (int n) {
// write code here
HashSet<Integer> columns=new HashSet<>();
HashSet<Integer> diagonals1=new HashSet<>();
HashSet<Integer> diagonals2=new HashSet<>();
return DFS(n,0,columns,diagonals1,diagonals2);
}
}