[算法题解详细]DFS解力扣51N皇后

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

示例1

请添加图片描述

输入:n = 4

输出:[[“.Q…”,“…Q”,“Q…”,“…Q.”],[“…Q.”,“Q…”,“…Q”,“.Q…”]]

解释:如上图所示,4 皇后问题存在两个不同的解法。

示例2

输入:n = 1

输出:[[“Q”]]

提示

  1. 1 <= n <= 9

  2. 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。

思路


这题我们可以用全排列的思想来做,首先初始化棋盘,然后遍历整个棋盘,对每个点进行判断,如果这个点是可以放置皇后的,则放置皇后,反之复原成初始值,下面我们进入代码

代码


首先在主函数中初始化棋盘,然后在类中定义一个ans容器用于存储答案

class Solution {

public:

vector<vector> ans;

int N;

vector<vector> solveNQueens(int n) {

ans.clear();

N = n;

vector chessboard(n, string(n, ‘.’));

dfs(0, chessboard);

return ans;

}

};

然后是dfs函数,出口条件还是当递归深度等于n的时候,将当前修改的棋盘插入ans容器中,然后是循环当前行,因为N皇后的规定一行只能有一个皇后,在循环中判断当前位置是否可放置皇后,这里要注意回溯的写法

void dfs(int u, vector& chessboard) {

if(u == N) {

ans.push_back(chessboard);

return;

}

for(int i = 0; i < N; i++) {

if(isOk(u , i, chessboard)){

chessboard[u][i] = ‘Q’;

dfs(u + 1, chessboard);

chessboard[u][i] = ‘.’;

}

}

}

然后是这个isOk()函数,我们传入行列和棋盘用于判断当前位置是否可以放置皇后

那么我们如何判断当前位置是否可放置皇后呢,这就需要看题目的规定:

任何两个皇后都不能处于同一条横行、纵行或斜线上。

横行这里我们不需要管了,因为如果横行有问题的话,会在后面发现不合适然后直接回溯

纵行我们通过传入的行列,让循环变量从0开始一直到当前列的前一列判断,如果这些位置有皇后的存在,则直接返回false,也就是传入的当前位置是不能放置皇后的,等循环结束后如果还没有返回,则进入下一个判断

bool isOk(int row, int col, vector& chessboard) {

for(int i = 0; i < row; i++) {

if(chessboard[i][col] == ‘Q’) {

return false;

}

}

}

下一个判断则是斜线,我们分成两种斜线,一个45度斜线一个135度斜线

首先看135度斜线

请添加图片描述

我们看坐标之间的关系,看上图,红色代表当前位置,斜线上方的位置就由当前位置的行-1,列-1得到

判断135度这条斜线上从起点到当前位置是否已经放置皇后,就需要我们从最上面开始一直遍历到当前位置,循环判断,如果已经有位置放置了皇后,则直接返回false,若循环结束还没有返回,表示当前135度斜线上是没有皇后的,就进入下一个判断

bool isOk(int row, int col, vector& chessboard) {

for(int i = 0; i < row; i++) {

if(chessboard[i][col] == ‘Q’) {

return false;

}

}

for(int i = row - 1 , j = col - 1; i >= 0 && j >= 0; i-- , j–) {

if(chessboard[i][j] == ‘Q’) {

return false;

}

}

}

下一个判断则是35度斜线

请添加图片描述

这条斜线坐标之间的关系也是十分清晰的,就是由当前位置的行-1,列+1得到

注意

这里要注意一点就是,如上图,我们不需要去遍历(1 , 2)这个当前位置下面的(2 , 1)和(3 , 1)两个位置,我们只需要遍历从(0, 3)到当前位置(1 , 2),等下一层或下下层递归下面的位置才会被遍历到

bool isOk(int row, int col, vector& chessboard) {

for(int i = 0; i < row; i++) {

if(chessboard[i][col] == ‘Q’) {

return false;

}

}

for(int i = row - 1 , j = col - 1; i >= 0 && j >= 0; i-- , j–) {

if(chessboard[i][j] == ‘Q’) {

return false;

}

}

for(int i = row - 1 , j = col + 1; i >= 0 && j < N; i-- , j++) {

if(chessboard[i][j] == ‘Q’) {

return false;

}

}

return true;

}

我们要注意在这些判断都没有返回false之后,我们要返回true表示当前位置是可以放置皇后的,因为我们已经判断了当前位置的横行,纵行,和左右斜线位置上都没有皇后的存在,是符合题目规则的。

最后把代码整合一下

完整代码:

class Solution {

public:

vector<vector> ans;

int N;

bool isOk(int row, int col, vector& chessboard) {

for(int i = 0; i < row; i++) {

if(chessboard[i][col] == ‘Q’) {

return false;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值