1.题目描述
The n-queens puzzle is the problem of placing n
queens on an n x n
chessboard such that no two queens attack each other.
Given an integer n
, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q'
and '.'
both indicate a queen and an empty space, respectively.
Example 1:
Input: n = 4 Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above
Example 2:
Input: n = 1 Output: [["Q"]]
Constraints:
1 <= n <= 9
2.题解
这里参考了中文leetcode平台的官方解答,
思路:2个皇后不能在同行、同列、两个方向的斜线上,n*n的棋盘必须放n个皇后,所以每行有1个皇后,第1行的皇后有n个位置可选,第2行有最多n-1个位置可选,依次类推,时间复杂度为O(N!);
判断2个皇后是否在同一条斜线上的方法:对于“左上-右下”方向,每一条斜线上的点的行列坐标之差相同,因此 “行-列” 可以代表这个方向的所有斜线;同理,对于“右上-左下”方向,“行+列” 可以代表这个方向的所有斜线。
时间复杂度:O(N!) (因为每行必有一个皇后,所以问题简化为列下标 0-n-1 的全排列问题。)
空间复杂度: O(N) (开辟一个大小为n的数组存储每行皇后的列下标)
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> solutions = new ArrayList<>();
//存储每行皇后所在的列下标
int[] queens = new int[n];
Arrays.fill(queens, -1);
//记录 左上-右下方向是否有皇后
Set<Integer> diagonals1 = new HashSet<Integer>();
//记录 右上-左下方向是否有皇后
Set<Integer> diagonals2 = new HashSet<Integer>();
//记录 该列是否有皇后
Set<Integer> columns = new HashSet<Integer>();
backtrack(solutions, queens, n, 0, columns, diagonals1, diagonals2);
return solutions;
}
public void backtrack(List<List<String>> solutions, int[] queens, int n, int row, Set<Integer> columns, Set<Integer> diagonals1, Set<Integer> diagonals2){
if(row == n){
List<String> board = generateBoard(queens, n);
solutions.add(board);
return;
}
for(int i = 0; i < n; i++){
//除去非法选择
if(columns.contains(i)){
continue;
}
int diagonal1 = row - i;
if(diagonals1.contains(diagonal1)){
continue;
}
int diagonal2 = row + i;
if(diagonals2.contains(diagonal2)){
continue;
}
//做选择
queens[row] = i;
columns.add(i);
diagonals1.add(diagonal1);
diagonals2.add(diagonal2);
//进入决策树的下一层
backtrack(solutions, queens, n, row+1, columns, diagonals1, diagonals2);
//撤销选择
queens[row] = -1;
columns.remove(i);
diagonals1.remove(diagonal1);
diagonals2.remove(diagonal2);
}
}
//生成要求的结果格式
public List<String> generateBoard(int[] queens, int n){
List<String> board = new ArrayList<String>();
for(int i = 0; i < n; i++){
char[] row = new char[n];
Arrays.fill(row, '.');
row[queens[i]] = 'Q';
board.add(new String(row));
}
return board;
}
}
3.解题框架和思路
(1)回溯问题的通用框架
对于n皇后问题,路径就是queens里存储的每行皇后已经放好的列下标,选择列表则是该行符合要求的剩余的列下标,n皇后的总体思路是从第1行到第n行确定每个皇后的列下标。
回溯问题的通用框架:
(2)n皇后问题的解
n的值 | 解的个数 |
1 | 1 |
2 | 0 |
3 | 0 |
4 | 2 |
5 | 10 |
6 | 4 |
7 | 40 |
8 | 92 |
9 | 352 |