代码随想录 回溯算法:N皇后
题目描述
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
题目链接:51
文章讲解:51
思考
一次一次的放,保证后一个和前一个不打架。每次都在下一行选择。
回溯函数 backtrack(row)
,它的任务是“在第 row
行,给皇后找个合适的位置”。
回溯三部曲
回溯函数的参数
- 当前要处理哪一行 (
int row
): 给第row
行找个位置”。 - 棋盘长啥样了 (
vector<string>& board
): 这个参数记录了之前的决策。它就像一张草稿纸,上面画着0到row-1
行的皇后都放在了哪儿。 - 最终结果集 (
vector<vector<string>>& result
): 收集所有符合条件的棋盘布局。这个也可以设置为全局变量,都可以
终止条件
当 row
增加到 n
的时候,意味着第 0, 1, 2, ..., n-1
行已经全部成功地、互不冲突地放上了皇后。
这不就找到了一个完整的、可行的解决方案吗!
所以,终止条件就是 row == n
。一旦满足这个条件,说明大功告成,把当前的 board
放进result`
单层搜索逻辑
在当前 row
这一行,一个固定的工作流程:“遍历选择 -> 判断 -> 做决定 -> 交给下一行 -> 撤销决定”。
遍历所有可能的选择: 在第
row
行,我们需要一个for
循环来遍历所有列。判断选择是否有效(剪枝): 对于
for
循环中的每一个col
,我们都得判断皇后放在(row, col)
这个位置,是否会与(0到row-1
行的皇后)冲突。写一个辅助函数isValid(row, col, board)
判断。执行“选择-前进-撤销”循环: 如果
isValid
判断通过,说明(row, col)
是一个当前看来可行的选择,正式进入“小三步”:处理节点(做出选择): 在棋盘的
(row, col)
位置放上皇后。board[row][col] = 'Q';
递归(前进): 既然这一行搞定了,那就把剩下的任务交给下一行。调用自身,去处理
row + 1
行。backtrack(n, row + 1, board, result);
回溯(撤销选择): 当上面那句
backtrack(row + 1, ...)
执行完毕返回时,意味着基于(row, col)
这个位置所能引发的所有后续可能性都已经被探索完了。我们必须把棋盘恢复原状,也就是把刚刚放在(row, col)
的皇后拿走,这样for
循环在下一次迭代(col + 1
)时,才能在一个干净的棋盘上尝试新的选择。board[row][col] = '.';
代码实现
class Solution {
public:
vector<vector<string>> result;
bool isValid(int row, int col, vector<string> chessboard, int n) {
// 检查列
for (int i = 0; i < row; i++) {
if (chessboard[i][col] == 'Q') {
return false;
}
}
// 检查 45度角是否有皇后
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
// 检查 135度角是否有皇后
for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
return true;
}
void backtracking(int n, int row, vector<string>& chessboard) {
if (row == n) {
result.push_back(chessboard);
return;
}
for (int col = 0; col < n; col++) {
if (isValid(row, col, chessboard, n)) {
chessboard[row][col] = 'Q';
backtracking(n, row + 1, chessboard);
chessboard[row][col] = '.';
}
}
}
vector<vector<string>> solveNQueens(int n) {
result.clear();
vector<string> chessboard(n, string(n, '.'));
backtracking(n, 0, chessboard);
return result;
}
};