The n-queens puzzle is the problem of placing n queens on an n×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:
Input: 4
Output: [
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],
["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.
解题思路:
在一行中的每一个位置 试探 是否可以放皇后,通过判断 对角线与列值是否有符合条件, 符合的话进入下一行位置判断(使用递归),如果此行放置皇后的位置不符合条件那么 回溯刚刚位置为’
.
,当row的值为n是意味着已经找到一组N—queens的组合 输出即可。整体就是DFS + 回溯的思想
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<string> t(n, string(n, '.'));
vector<vector<string>> v;
solve(v, t, 0);
return v;
}
// row 表示行 对行进行递归
void solve(vector<vector<string>> &v, vector<string> &t, int row){
if(row == t.size()){
v.push_back(t);
return;
}
for(int col = 0; col < t.size(); col++){
//尝试此位置可否放置皇后
t[row][col] = 'Q';
if(IsValid(t, row, col)) solve(v, t, row + 1);
//不满足条件回溯
t[row][col] = '.';
}
}
bool IsValid(vector<string> &t, int row, int col){
bool valid = true;
for(int i = 0; i < row && valid; valid = t[i++][col] != 'Q');
for(int i = row, j = col; valid && i-- && j--; valid = t[i][j] != 'Q');
for(int i = row, j = col; valid && i-- && ++j < t.size(); valid = t[i][j] != 'Q');
return valid;
}
};
优化版本:
还是同样的思想,改进两个点
- 通过一个queens 数组来保存每行中Q的列的位置,例如图中的solution1 queens = {1, 3, 0, 2}, 行对应的列的位置,也就是说queens数组中没有重复的值 表示符合条件。
- 判断对角线的位置时,有一个规律;如果两点的行的差的绝对值等于列的差的绝对值那么他们 在同一对角线上 这样可以简化对角先的 判断
C++ version:
class Solution{
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> v;
vector<int> queens(n);
solve(v, queens, 0);
return v;
}
void solve(vector<vector<string>> &v, vector<int> &queens, int row){
int n = queens.size();
//满足条件时,给v赋值
if(row == n){
vector<string> t(n, string(n, '.'));
for(int i = 0; i < n; i++){
t[i][queens[i]] = 'Q';
}
v.push_back(t);
return;
}
//试探当前行的每个位置
for(int col = 0; col < n; col++){
queens[row] = col;
if(isValid(queens, row)) solve(v, queens, row + 1);
}
}
bool isValid(vector<int> &queens, int row){
for(int i = 0; i < row; i++){
// 如果列上不符合条件 或者 对角线上
if(queens[row] == queens[i] || abs(queens[row] - queens[i]) == abs(i - row)){
return false;
}
}
return true;
}
};
java version:
class Solution {
public List<List<String>> solveNQueens(int n) {
List<List<String>> ans = new ArrayList<>();
if(n <= 0) return ans;
solve(ans,new int[n], 0);
return ans;
}
public void solve(List<List<String>>res, int[] queens, int row) {
int n = queens.length;
if(row == n) {
List<String> t = new ArrayList<>();
for(int i = 0; i < n; i++) {
String st = "";
for(int j = 0; j < n; j++) {
if(queens[i] == j) st += 'Q';
else st += '.';
}
t.add(st);
}
res.add(t);
return;
}
for(int col = 0; col < n; col++) {
queens[row] = col;
if(IsValid(queens, row)) {
solve(res, queens, row + 1);
}
}
}
public boolean IsValid(int [] queens , int row) {
for(int i = 0; i < row; i++) {
if(queens[row] == queens[i] || Math.abs(queens[i] - queens[row]) == Math.abs(i - row)) {
return false;
}
}
return true;
}
}