需求I:
n皇后问题,有一个n*n的棋盘,有n个皇后,要保证每个皇后不能在同一行、同一列、同一对角线,这样才不会出现冲突,求解n皇后共有多少种放置方式。
分析:
1、创建n*n的char型二维数组,初始化为'.',表示没有放置皇后。
2、因为皇后不能在同一行,所以将皇后i放到行i,逐行确定每个皇后的位置。假设,现在要确定皇后num(num的范围是0~n-1)的位置,如果num==n,那么说明已经找到了一个可行解,将该数组转化成字符串集合,添加到结果集合中即可。如果num<n,那么该皇后可以放置的位置有[0, n-1],假设放到位置i处,判断[num][i]处放置皇后是否合法,如果合法,将[num][i]置为'Q',然后寻找皇后num+1的位置,然后将[num][i]置为'.',继续判断皇后num是否可以放到其它位置。如果不合法,那么继续判断皇后是否可以放到其它位置。
3、判断皇后的位置是否合法。因为每个皇后都位于不同行,所以只需要判断皇后的位置是否位于同一列或者同一对角线即可。对于皇后num,只需要判断比num小的皇后的位置即可。假如两个皇后的位置分别是[i1][j1]和[i2][j2],那么只需要保证j1 != j2(不在同一列),并且|i1-i2| != |j1-j2|(不在同一对角线)即可。
4、将二维字符数组转成字符串集合。创建字符串集合,将二维数组的每一行转成字符串,添加到集合中即可。
代码:
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> res = new LinkedList<List<String>>();
//创建n*n数组,初始化为'.'
char[][] board = new char[n][n];
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
board[i][j] = '.';
//求皇后0的位置
dfs(0, board, res);
return res;
}
//确定皇后num的位置
public void dfs(int num, char[][] board, List<List<String>> res){
//如果num==board.length,说明已经找到了可行解,将其添加到res中
if(num == board.length){
res.add(arraytolist(board));
return;
}
//确定皇后num放置的位置
for(int i = 0; i < board.length; i++){
if(valid(num, i, board)){
board[num][i] = 'Q';
dfs(num+1, board, res);
board[num][i] = '.';
}
}
}
//判断皇后num的位置是否合法
public boolean valid(int num, int col, char[][] board){
for(int i = 0; i < num; i++){
for(int j = 0; j < board.length; j++){
if(board[i][j] == 'Q'){
if(j == col || Math.abs(i-num) == Math.abs(j-col))
return false;
}
}
}
return true;
}
//将二维字符数组转化成字符串集合
public List<String> arraytolist(char[][] board){
List<String> res = new LinkedList<String>();
for(int i = 0; i < board.length; i++)
res.add(new String(board[i]));
return res;
}
}
需求II:
n皇后问题,求总的排列个数。
分析:
相对于上述问题,不需要将所有可行解存储起来,只需要记录个数即可,思路相同,更简单一些。
代码:
class Solution {
//相对于NQueens I来说,不需要创建集合来存储结果,只需要一个变量,来递增数量即可
int res = 0;
public int totalNQueens(int n) {
//创建n*n二维字符数组,初始化为'.'
char[][] board = new char[n][n];
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
board[i][j] = '.';
dfs(0, board);//确定皇后0的位置
return res;
}
public void dfs(int num, char[][] board){
if(num == board.length)
{
res++;//已经找到了一个可行解
return;
}
for(int i = 0; i < board.length; i++){
if(valid(num, i, board)){
board[num][i] = 'Q';
dfs(num+1, board);
board[num][i] = '.';
}
}
}
public boolean valid(int num, int col, char[][] board){
for(int i = 0; i < num; i++){
for(int j = 0; j < board.length; j++){
if(board[i][j] == 'Q'){
if(j == col || Math.abs(i-num) == Math.abs(j-col))
return false;
}
}
}
return true;
}
}