代码随想录——回溯 N皇后
思路
每次递归都遍历第0到n-1列,判断当前位置是否合法——确保不会和之前的皇后同列、同斜线(同行已经通过递归避免了)
那么核心就是
- 怎么判断是否合法
- 怎么返回答案
2反而比较重要,因为我一开始就设了个vector<int> queen,表示第i个皇后在第queen[i]列。但这在本题不好用,之后还得根据queen再生成string数组的答案。如果返回值是vector<vector<int>> 那么可以用。
1的基础方法简单
- 本题这种string保存的就查看同列/斜线是否有‘Q’
- 如果返回int数组的,就用坐标数学关系判断:同列则纵坐标相同,同斜线则 abs(横坐标差)=abs(纵坐标差)
但以上方法是O(N)的复杂度,还可以优化为O(1)。本次暂时不写。
代码
下面是两种返回类型的答案
vector<vector<string>>
class Solution {
public:
vector<vector<string>> result;
void backtracking(vector<string>& queen,int n,int k){
if(k == n){
result.emplace_back(queen);
return;
}
for(int col=0;col<n;col++){//遍历第k行第col列
if(isValid(k,col,queen,n)){
queen[k][col] = 'Q';
backtracking(queen,n,k+1);
queen[k][col] = '.';
}
}
}
bool isValid(int row,int col,vector<string>& queen,int n){
//检查列
for(int i=0;i<row;i++){
if(queen[i][col] == 'Q')return false;
}
//检查左斜线
for(int i=row-1,j=col+1;i>=0 && j<n;i--,j++){
if(queen[i][j] == 'Q')return false;
}
//检查右斜线
for(int i=row-1,j=col-1;i>=0 && j>=0;i--,j--){
if(queen[i][j] == 'Q')return false;
}
return true;
}
vector<vector<string>> solveNQueens(int n) {
// vector<int> queen(n);//第0个皇后(一定在第0行)在第queen[0]列
result.clear();
vector<string> queen(n,string(n,'.'));
backtracking(queen,n,0);
return result;
}
};
vector<vector<int>>
class Solution {
public:
vector<vector<int>> result; // 存储所有的解,每个解是一个位置数组
void backtracking(int n, int row, vector<int>& queen) {
if (row == n) { // 所有皇后都放置完成
result.push_back(queen); // 将当前解添加到结果中
return;
}
for (int col = 0; col < n; col++) {
if (isValid(row, col, queen)) {
queen[row] = col; // 将第row行的皇后放在col列
backtracking(n, row + 1, queen); // 递归放置下一个皇后
queen[row] = -1; // 回溯,撤销当前放置的皇后
}
}
}
bool isValid(int row, int col, const vector<int>& queen) {
for (int i = 0; i < row; i++) {
// 检查列冲突
if (queen[i] == col) return false;
// 检查斜线冲突
if (abs(queen[i] - col) == abs(i - row)) return false;
}
return true;
}
vector<vector<int>> solveNQueens(int n) {
result.clear();
vector<int> queen(n, -1); // 用来存储皇后的位置,-1表示尚未放置
backtracking(n, 0, queen);
return result;
}
};