另外两道之后再写
51. N皇后
N皇后问题,算是dfs最经典的问题了,数据结构课一定会碰到的问题。
简单来说就是N*N的矩阵中,在任一行,列,对角线,都只允许出现一个皇后。
尽管在力扣上是困难题,其实这个题就是判断条件比较复杂
1.判断条件
n皇后的判断条件就是四个:
- 行唯一
- 列唯一
- 对角线唯一
- 反对角线唯一
我们可以为所有行、列、对角线、反对角线设置一个bool数组,用来记录是否当前行、列、对角线、反对角线已经有皇后
额外一提,当棋盘为 n,行列数为 n,对角线数为 2*n - 1,根据行列可以计算所在的对角线数
根据行列计算对角线数这个建议自己去琢磨,把这个攻破了这题其实和一般的回溯没什么区别
2.自己写的
vector<vector<string>> res;
vector<string> path;
vector<bool> row;
vector<bool> col;
vector<bool> diag;
vector<bool> back_diag;
void backtracing(int n, int cur_row)
{
if (path.size() == n)
{
res.push_back(path);
return;
}
string str(n, '.');
for (int cur_col = 0; cur_col < n; cur_col++)
{
if (col[cur_col] == false && diag[n - 1 - cur_col + cur_row] == false && back_diag[cur_row + cur_col] == false)
{
row[cur_row] = true;
col[cur_col] = true;
diag[n - 1 - cur_col + cur_row] = true;
back_diag[cur_row + cur_col] = true;
str[cur_col] = 'Q';
path.push_back(str);
backtracing(n, cur_row + 1);
path.pop_back();
str[cur_col] = '.';
row[cur_row] = false;
col[cur_col] = false;
diag[n - 1 - cur_col + cur_row] = false;
back_diag[cur_row + cur_col] = false;
}
}
}
vector<vector<string>> solveNQueens(int n) {
res.clear();
path.clear();
for (int i = 0; i < n; i++)
{
row.push_back(false);
col.push_back(false);
}
for (int i = 0; i < 2 * n - 1; i++)
{
diag.push_back(false);
back_diag.push_back(false);
}
backtracing(n, 0);
return res;
}
3.代码随想录的方法
代码随想录是把这个判别写了一个函数单独拎出来,然后用遍历的方式去检查,和我的思路还是不太一样,所以不妨写写看
这个方法中不再有那些布尔数组,而是直接利用模拟棋盘判断
注意,这个模式下不用检查同行,因为同行中只会出现一个
vector<vector<string>> res;
vector<string> chessboard; //棋盘
void backtracing(int n, int cur_row)
{
if (cur_row == n)
{
res.push_back(chessboard);
return;
}
for (int cur_col = 0; cur_col < n; cur_col++)
{
if (isValid(cur_row, cur_col, n))
{
chessboard[cur_row][cur_col] = 'Q';
backtracing(n, cur_row + 1);
chessboard[cur_row][cur_col] = '.';
}
}
}
bool isValid(int row, int col, int n)
{
int i, j;
//检查同列
for (i = 0, j = col; i < n; i++)
if (chessboard[i][j] == 'Q')
return false;
//检查正对角线
for (i = row, j = col; i > 0 && j > 0; i--, j--);
for (;i < n && j < n; i++, j++)
if (chessboard[i][j] == 'Q')
return false;
//检查反对角线
for (i = row, j = col; i > 0 && j < n; i--, j++);
for (;i < n && j > 0; i++, j--)
if (chessboard[i][j] == 'Q')
return false;
return true;
}
vector<vector<string>> solveNQueens(int n) {
res.clear();
chessboard.clear();
for (int i = 0; i < n; i++)
chessboard.push_back(string(n, '.'));
backtracing(n, 0);
return res;
}
4.比较怪的写法
我在学数据结构的时候,老师讲过可以用每一个格子每一个格子的方式深度优先,每个格子要么放,要么不放。但是这个树看起来估计会很大(深度n*n)
速度确实慢中慢哈哈哈
这个记得是要检查同行的,而且需要记录放的皇后数量,来确认是否为目标结果
vector<vector<string>> res;
vector<string> chessboard; //棋盘
void backtracing(int n, int cur_row, int cur_col, int cnt)
{
if (cur_row >= n)
{
if (cnt == n) res.push_back(chessboard);
return;
}
int next_row = cur_row;
int next_col = cur_col;
if (cur_col < n - 1)
next_col++;
else
{
next_row++;
next_col = 0;
}
backtracing(n, next_row, next_col, cnt);
if (isValid(cur_row, cur_col, n))
{
chessboard[cur_row][cur_col] = 'Q';
backtracing(n, next_row, next_col, cnt + 1);
chessboard[cur_row][cur_col] = '.';
}
}
bool isValid(int row, int col, int n)
{
int i, j;
//检查同列
for (i = 0, j = col; i < n; i++)
if (chessboard[i][j] == 'Q')
return false;
//检查同行
for (i = row, j = 0; j < n; j++)
if (chessboard[i][j] == 'Q')
return false;
//检查正对角线
for (i = row, j = col; i > 0 && j > 0; i--, j--);
for (;i < n && j < n; i++, j++)
if (chessboard[i][j] == 'Q')
return false;
//检查反对角线
for (i = row, j = col; i > 0 && j < n; i--, j++);
for (;i < n && j > 0; i++, j--)
if (chessboard[i][j] == 'Q')
return false;
return true;
}