LeetCode N皇后
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
说明:皇后之间不能互相攻击,表示皇后与皇后之间不能同处于同一行、同一列、同一斜线上。
思路分析:首先对于不能放在同一行、同一列的规则,我们每次在一行只放置一个,那么只要在用一个标记标记第i列是否已放置,那么这样就保证了放置的皇后不会在同一行或者同一列。
算法选择**“回溯法”(深度优先搜索)**,即从行下标0到n,从小到大进行每一行放置,每一行进行搜索放置的时候标记放置的列,然后每次检查的时候只需要检查刚刚放进去的皇后是否会攻击到其他的皇后。并且由于保证了不同行,不同咧,所以只要检查左斜线,右斜线上是否有皇后。
皇后检测示意图
class Solution {
public:
vector<vector<string> >result;//用于存储结果
vector<bool> colFlag;//用于标记i列是否使用
vector<vector<string>> solveNQueens(int n) {
result.clear();
if (n == 0){
return result;
}
colFlag = vector<bool>(n, false);
vector<string> tempResult(n, string(n,'.'));//一个中间结果
solveDFS(tempResult, 0);//深度搜索求解
return result;
}
//回溯法(深度优先搜索)
void solveDFS(vector<string> &tempResult, int steps){
int n = tempResult.size();
if (steps == n){//如果已经放置完n个
result.push_back(tempResult);
}
else{
for (int col = 0; col < n; ++col){//在steps行中选取一个未使用过的列
if (colFlag[col] == false){//如果此列未使用过
tempResult[steps][col] = 'Q';//放置皇后
colFlag[col] = true;//标记使用
if (isOK(tempResult, steps, col)){//如果放置的这个仍然不攻击,才能进行下一个皇后的放置
solveDFS(tempResult, steps + 1);
}
tempResult[steps][col] = '.';//记得移除皇后
colFlag[col] = false;//标记为使用
}
}
}
}
//判断在steps行col列放置皇后后是否会出现攻击现象
bool isOK(vector<string> &tempResult, int steps, int col){
//由于放置的时候就保证了皇后之间不会处于同一行、同一列
//所以判断攻击与否只要判断是否出现同一斜线上
int left = col - 1;//判断左边斜线
int right = col + 1;//右边斜线
int n = tempResult.size();
for(int row = steps - 1; row >= 0; --row, --left, ++right){
if (left >= 0 && tempResult[row][left] == 'Q'){
return false;
}
if (right < n && tempResult[row][right] == 'Q'){
return false;
}
}
return true;
}
};
如果看不太明白,多琢磨琢磨,最号自己在纸上模拟一下回溯法的运行。
我以前也老是写不出皇后放置问题的代码,现在20分钟撸出了上面的代码,如果实在理解不了,那就证明自己的逻辑思维还不够,需要更多的编程训练。