1. 题目
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.
For example,
There exist two distinct solutions to the 4-queens puzzle:
[
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."],
["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
]
2. 思路
回溯的方式求解。第一步将左上顶点置位作为起始点。第一个点一定是有效位。然后每次试探的为下一行找到合适的位置,如果找到了递归的继续找下一行,如果下一行超过了N,则说明得到一个有效解。如果下一行找不到合适的位置,或者是已经找到了有效解,则改为从当前最后一行的当前有效位置的下一个位置开始往后试探,扎到一个新的有效位置。如果在当前行找不到,则回退这一行,从上一行的位置开始往后找。如果一直回退到全部-1行,则全部递归完成。
试探某一个位置是否有效,通过已有的皇后影响的位置来判断。如果[i, j]位置有皇后,从二维坐标平面上考虑,影响的空间实际上是x=i; y=j; x+y=i+j; x-y=i-j四条线段覆盖的所有的点。可以通过四个数组来标记。
3. 代码
耗时:113ms
// 棋盘的横坐标是x,纵坐标是y。
// 横、纵、左斜、右斜四个方向可以用四个一次函数表示
// 对于坐标[i,j ]对应的四条线分别是:
// 横线可以用x=i [0,n-1]
// 纵线是y=j [0,n-1]
// 反斜线是x-y=i-j [-n+1,n-1]
// 正斜线是x+y=i+j [0,2n-2]
// 因此用四个数组可以表示这棋盘上所有被杀点, 在实现时为了方便可以用一个长度为6n-2的数组来存储
class ChessBoard {
public:
bool* kill; // x,y,x-y,x+y分别对应区段为[0,n)[n,2n)[2n,4n-1)[4n,6n-1)
int n;
ChessBoard(int N) : kill(NULL), n(N) {
kill = new bool[6*N];
for (int i = 0; i < 6*N; i++) {
kill[i] = false;
}
}
~ChessBoard() {
delete[] kill;
}
vector<int> four_lines(int i, int j) {
vector<int> l;
l.push_back(i);
l.push_back(n + j);
l.push_back(2 * n + i -j + n -1);
l.push_back(4 * n + i + j);
return l;
}
void add(int i, int j) {
vector<int> pos = four_lines(i, j);
for (int k = 0; k < 4; k++) {
kill[pos[k]] = true;
}
}
void del(int i, int j) {
vector<int> pos = four_lines(i, j);
for (int k = 0; k < 4; k++) {
kill[pos[k]] = false;
}
}
bool valid(int i, int j) {
vector<int> pos = four_lines(i, j);
for (int k = 0; k < 4; k++) {
if (kill[pos[k]]) {
return false;
}
}
return true;
}
};
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> ret;
ChessBoard cb(n);
vector<int> ans; // 第i个元素存储第i+1行的列号
ans.push_back(0);
cb.add(0, 0);
//cout << "start i=0 j=0" << endl;
while (!ans.empty()) {
if (tryNQueens(cb, ans)) { // 在一个有效的部分布局下填充下一个行
if (ans.size() == cb.n) {
fill(ret, ans);
move_next(cb, ans);
}
} else {
move_next(cb, ans);
}
}
return ret;
}
void move_next(ChessBoard& cb, vector<int>& ans) {
if (ans.size() == 0) { return ;}
while (ans.size() != 0) {
int i = ans.size() - 1;
int j = ans.back();
ans.pop_back();
cb.del(i, j);
j++;
for (; j < cb.n; j++) {
if (cb.valid(i, j)) {
ans.push_back(j);
cb.add(i, j);
//cout << "move next pos: i=" << i << " j=" << j << endl;
return ;
}
}
//cout << "rool back row=" << ans.size() << endl;
}
return ;
}
bool tryNQueens(ChessBoard& cb, vector<int>& ans) {
if (ans.size() == cb.n) {
return true;
}
int i = ans.size();
for (int j = 0; j < cb.n; j++) {
if (cb.valid(i, j)) {
ans.push_back(j);
cb.add(i, j);
//cout << "try next row: i=" << i << " j=" << j << endl;
return true;;
}
}
//cout << "try fail, i=" << i << endl;
return false;
}
void fill(vector<vector<string>>& ret, vector<int>& ans) {
//cout << "[Find]" << endl;
string temp;
for (int i = 0; i < ans.size(); i++) {
temp += ".";
}
vector<string> str_ans;
for (int i = 0; i < ans.size(); i++) {
string s = temp;
s[ans[i]] = 'Q';
str_ans.push_back(s);
//cout << s << endl;
}
ret.push_back(str_ans);
return ;
}
};
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。