1、回溯
我们可以利用回溯搜索所有的可能。我们利用数组column
记录每一列的使用情况,数组ldiag(2 * n - 1, false)
记录主对角线上的使用情况,数组rdiag(2 * n - 1, false)
记录副对角线上的使用情况。值得注意的是,我们主对角线上的序号是自左下到右上,副对角线上的序号是自左上到右下。
在回溯当中,我们按照每行寻找有无可以放置的位置,若此时行数等于总行数则直接将当前结果压入最终结果中。否则我们首先判断当前列、主对角线和副对角线上的所在列是否有人占用,有则直接跳过,否则我们将当前节点位置修改为Q
并递归调用函数。递归结束后我们将当前节点的状态改回为之前的状态并修改矩阵的值。
class Solution {
public:
// 辅函数
void backtracking(vector<vector<string>> &ans, vector<string> &board, vector<bool> &column, vector<bool> &ldiag, vector<bool> &rdiag, int row, int n) {
if (row == n) {
ans.push_back(board);
return;
}
for (int i = 0; i < n; ++i) {
if (column[i] || ldiag[n - row + i - 1] || rdiag[row + i]) {
continue;
}
// 修改当前节点状态
board[row][i] = 'Q';
column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = true;
// 递归子节点
backtracking(ans, board, column, ldiag, rdiag, row + 1, n);
// 回改当前节点状态
board[row][i] = '.';
column[i] = ldiag[n - row + i - 1] = rdiag[row + i] = false;
}
}
// 主函数
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> ans;
if (n == 0) {
return ans;
}
vector<string> board(n, string(n, '.'));
vector<bool> column(n, false), ldiag(2 * n - 1, false), rdiag(2 * n - 1, false);
backtracking(ans, board, column, ldiag, rdiag, 0, n);
return ans;
}
};