leetcode 51 N皇后问题
1 基于集合的回溯
- 1 每次调用都是对给定row的位置求解。
- 2 皇后所在的列column 跟 其主对角线、副对角线的位置都可以用一个数值表示,记录了已摆放好的k个皇后的column、主对角线、副对角线就记录了棋盘上已被占据的势力范围。
- 3 此处queens和columns存放数据的逻辑是一样的,之所以用两个数据结构重复存储相同的值,原因是:1)vector数据类型是按顺序存取,后续用[…Q…]字符串表示solution时会用到数据的下标所蕴含的信息,此时不可用hash映射的unorderd_set数据类型;2)unorderd_set数据类型是hash存储,其优点是查询快。
- 4 【精妙的递归】 不管是1)下一皇后无法摆放而溯回 还是2)N皇后已摆放整齐而溯回,当递归返回时,栈都会回溯,直到所有的solutions找到为止。
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
auto solutions = vector<vector<string>>();
auto queens = vector<int >(n, -1);
auto columns = unordered_set<int>();
auto diagonals1 = unordered_set<int>();
auto diagonals2 = unordered_set<int>();
backtrack(solutions, queens, n, 0, columns, diagonals1, diagonals2);
}
void backtrack(vector<vector<string>> &solutions, vector<int> &queens, int n, int row,
unordered_set<int> &columns, unordered_set<int> &diagonals1, unordered_set<int> &diagonals2) {
if (row == n) {
vector<string> board = generateBoard(queens, n);
solutions.push_back(board);
} else {
for (int i = 0; i < n; i++) {
if (columns.find(i) != columns.end())
continue;
int diagonal1 = row - i;
if (diagonals1.find(diagonal1) != diagonals1.end())
continue;
int diagonal2 = row + i;
if (diagonals2.find(diagonal2) != diagonals2.end())
continue;
queens[row] = i;
columns.insert(i);
diagonals1.insert(diagonal1);
diagonals2.insert(diagonal2);
backtrack(solutions, queens, n-1, 1, columns, diagonals1, diagonals2);
queens[row] = -1;
columns.erase(i);
diagonals1.erase(i);
diagonals2.erase(i);
}
}
}
vector<string> generateBoard(vector<int> &queens, int n) {
auto board = vector<string>();
for (int i = 0; i < n; i++) {
string row = string(n, '.');
row[queens[i]] = 'Q';
board.push_back(row);
}
return board;
}
};