这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
题目
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
解析
其实跟数独问题有些类似,因此我们先来思考:
- 如何解决这个问题?
事实上我们需要考虑的地方在于:
- 每行,每列,两条对角线不能有重复
因此我们需要记录上一次填到哪里了,此处我们第一直觉当然是使用预计的nxn数组a来记录,预计是这样的:
if(check){
paint(a,x,y)
//doNext
unpaint(a,x,y)
}
确定这个位置可以填之后,我们直接将相关不能填的都给赋值,然后执行下一次递归;递归结束后,我们将a复原。这样做的好处是:我们下一次检查,只要检查对应格子是否已被赋值就可以了。
但这个a的复原,如果a是二维数组的话是很难做的,原因如下:
- 因为我们不清楚我们复原的格子,和原来其他的格子上面的是否有相交,因此还需要做额外的工作来检查其他的格子。
而且,注意到我们只关心那些填了数的格子,并且出于关系:
- NxN的棋盘放n个皇后
因此我们知道:
- 每行有且仅有一个皇后
因此我们使用一维数组rec[n],来记录我们之前已经填过的数。
- 我们从前往后进行遍历,我们需要检查:对角线和列上的数即可,因为我们知道我们在每一行上填的数都是唯一的。
代码
public static List<List<String>> solveNQueens(int n) {
List<List<String>> res = new ArrayList<>();
int[] rec = new int[n];
Arrays.fill(rec,-20);
test(rec,0,res,n);
return res;
}
private static void test(int[] rec, int curLine, List<List<String>> res,int total) {
if(curLine == total){
List<String> cur = new ArrayList<>();
for (int i = 0; i < rec.length; i++) {
StringBuilder sb = new StringBuilder();
for (int i1 = 0; i1 < total; i1++) {
sb.append(i1==rec[i]?"Q":".");
}
cur.add(sb.toString());
}
res.add(cur);
return;
}
for (int i = 0; i < total; i++) {
if(check(rec,curLine,i)){
rec[curLine] = i;
test(rec,curLine+1,res,total);
rec[curLine] = -20;
}
}
}
private static boolean check(int[] rec,int x,int y){
for (int i = 0; i <= x; i++) {
if(rec[x-i]== y ||rec[x-i] == y-i || rec[x-i] == y+i) return false;
}
return true;
}
执行用时:2 ms, 在所有 Java 提交中击败了93.97%的用户
内存消耗:38.6 MB, 在所有 Java 提交中击败了65.71%的用户