一、题目:51. N皇后
二、题目解析
改题属于,递归加回溯的题目,题意是在N*N的棋盘上,如何放置N个皇后,使其不能在同一行,同一列,以及斜对角线上。
解法1:
假设我们要检查(4,3)这个位置,由于皇后是按行摆放的,所以就不用检查一行了。
由于是从上到下摆放,第5行、第6行、第7行还没有皇后,那么Q往下的竖线、斜线都不用检查。
竖线部分只要检查(3,3)、(2,3)、(1,3)、(0,3)这几个位置就可以了。
Q左边那条斜线,不断往左上方遍历,坐标变化是(3,2)、(2,1)、(1,0),每次都是x-1,y-1。
Q右边那条斜线,不断往右上方遍历,坐标变化是(3,4)、(2,5)、(1,6)、(0,7),每次都是x-1,y+1。
所以三个循环,一个检查竖线、一个检查左边斜线、一个检查右边斜线,就完成了整个校验过程。
以4 * 4格子的递归调用树如下:
三、代码如下:
class Solution {
public List<List<String>> solveNQueens(int n) {
//生成N*N的棋盘
char[][] arr = new char[n][n];
//填充棋盘,每个格子默认是“.”表示没有放置皇后
for(int i=0;i<n;++i) {
Arrays.fill(arr[i],'.');
}
List<List<String>> res = new ArrayList<List<String>>();
dfs(arr,0,n,res);
return res;
}
//检查当前的行和列是否可以放置皇后
private boolean check(char[][] arr,int x,int y,int n) {
//检查竖着的一列是否有皇后
for(int i=0;i<x;++i) {
if(arr[i][y]=='Q') {
return false;
}
}
//检查左上到右下的斜边是否有皇后
int i=x-1, j=y-1;
while(i>=0 && j>=0) {
if(arr[i][j]=='Q') {
return false;
}
--i;
--j;
}
//检查左下到右上的斜边是否有皇后
i = x-1;
j = y+1;
while(i>=0 && j<n) {
if(arr[i][j]=='Q') {
return false;
}
--i;
++j;
}
return true;
}
private void dfs(char[][] arr,int x,int n,List<List<String>> res) {
//x是从0开始计算的,当x==n时所有行的皇后都放置完毕,此时记录结果
if(x==n) {
List<String> ans = new ArrayList<String>();
for(int i=0;i<n;++i) {
StringBuilder tmp = new StringBuilder();
for(int j=0;j<n;++j) {
if(arr[i][j]=='.') {
tmp.append(".");
} else {
tmp.append("Q");
}
}
ans.add(tmp.toString());
}
res.add(ans);
return;
}
//遍历每一列
for(int y=0;y<n;++y) {
//检查[x,y]这一坐标是否可以放置皇后
//如果满足条件,就放置皇后,并继续检查下一行
if(check(arr,x,y,n)) {
arr[x][y] = 'Q';
dfs(arr,x+1,n,res);
arr[x][y] = '.';
}
}
}
}
四、测试
五、结束
六、详细解答