N皇后
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n皇后问题,研究的是如何将n个皇后,放置在n×n的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数n,返回所有不同的解决方案。
'Q' : 代表皇后,'.' : 代表空位。
其中,1 <= n <= 9。
示例 1:
输入:n = 4 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 解释:如上图所示,4 皇后问题存在两个不同的解法。
示例 2:
输入:n = 1 输出:[["Q"]]
解体思路
这道题关键的点在于,同一行、同一列、同一斜线上,不能有相同的皇后。
从整体上来看
- 我们在第一行第一列放置一个皇后
- 接着我们遍历到第二行,然后从左往右,排除不能放置皇后的位置(第一列,第二列),在第三列上放置皇后
- 然后遍历到下一行
- 遍历当前行,排除不能放置皇后的列,在后面的列放置皇后,如果已经遍历完全部的行,我们记录答案。如果行遍历完了或者没有可放置的列了,就进行5的操作;如果行没有遍历完,我们继续3的操作
- 接着我们回溯到上一行,然后继续4的操作
从细节上来看
- 我们需要在n×n的棋盘上,放置n个皇后,所以可以用长度为n的一维数组存放皇后,其中元素值代表的是每个皇后放置的位置,最后作为答案时,把数组调整成题目需要的结构,然后返回。
- 因为相同的列上,只能放置一个皇后,我们用长度为n的一维数组记录,如果放置了皇后,我们把这个位置标记成1。
- 然后在斜上排除位置,斜着的位置分为左斜和右斜
- 我们先看左斜,如果在(row, col)的位置上放置了皇后,那么(row + 1, col - 1)的位置上不能放置皇后了,同样的(row + 2, col - 2)的位置上也不能放置皇后,我们可以用row + col来代表这些位置,标记成了1代表位置已经被放置了,那么记录的数据长度需要多大呢,最大的位置是(n - 1) + (n - 1) = 2 * n - 2。数组的大小就设置为2 * n - 2么?注意这里有个细节点,数组的下表是从0开始的,所以如果我们想标记到2 * n - 2 的位置,那么数组的长度需要设置为2 * n - 1,数组应该初始化为new int[2 * n - 1]。
- 我们再看右斜,如果在(row, col)的位置上放置了皇后,那么(row + 1, col + 1)的位置上不能放置皇后了,同样的(row + 2, col + 2)的位置上也不能放置皇后,也就是需要把row + col的位置上标记成1,row + col + 2的位置上也要标记成1,以此类推......这样的话,我们就需要用二维组来记录了。那么能不能就像左斜一样,用一维数组就可以记录了呢?这个时候我们需要找一下规律了,如果我们用row - col作为位置,是不是就可以表示(row + 1, col + 1)、(row + 2, col + 2)了?所以我们用row - col来记录,考虑到-n + 1 <= row - col <= n - 1,数组下标不能为负数,所以row - col需要整体的偏移n - 1,也就是 0 <= row - col + n - 1 <= 2 * n - 2,最后数组的长度也为2 * n - 1。
具体代码如下:
class Solution {
int n;
int[] rows;
int[] hills;
int[] dales;
int[] queens;
List<List<String>> ans = new ArrayList();
public List<List<String>> solveNQueens(int n) {
this.n = n;
rows = new int[n];
hills = new int[2 * n - 1];
dales = new int[2 * n - 1];
queens = new int[n];
backtrack(0);
return ans;
}
public void backtrack(int row){
for(int col = 0; col < n; col++){
if(isNotUnderAttack(row, col)){ // 不会被攻击
placeQueen(row, col); // 放置皇后
if(row + 1 == n)addSolution(); // 放置到了最后一行就记录答案
else backtrack(row + 1); // 否则继续递归
removeQueen(row, col); // 移除皇后
}
}
}
private boolean isNotUnderAttack(int row, int col){
int res = rows[col] + hills[row - col + n - 1] + dales[row + col];
return (res == 0)? true : false;
}
private void placeQueen(int row, int col){
queens[row] = col;
rows[col] = 1;
hills[row - col + n - 1] = 1;
dales[row + col] = 1;
}
private void removeQueen(int row, int col){
queens[row] = 0;
rows[col] = 0;
hills[row - col + n - 1] = 0;
dales[row + col] = 0;
}
private void addSolution(){
List<String> solution = new ArrayList<String>();
for(int i = 0; i < n; i++){
int col = queens[i];
StringBuilder sb = new StringBuilder();
for(int j = 0; j < col; j++)sb.append(".");
sb.append("Q");
for(int k = 0; k < n - col - 1; k++)sb.append(".");
solution.add(sb.toString());
}
ans.add(solution);
}
}