一、题目描述:
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 示例1:
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
示例2:
输入:n = 1
输出:[["Q"]]
提示: 1 <= n <= 9
皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
二、思路分析:
N皇后问题是一道经典的回溯算法题目。回溯算法是一个类似枚举的搜索尝试过程,在搜索尝试过程中寻找问题的解。当发现不满足求解条件的时候就回溯返回,尝试别的路径。做题的模版如下:
- 首先写好跳出条件,符合条件的时候才放入返回结果中
- 已经算过的数进行标记,不再计算
- 往下遍历,结束后返回上一步。 伪码如下:
let res = [];
const DFS = ()=>{
if(满足结束条件){
res.push(路径)
return;
}
for(遍历选择列表){
去掉已经选择过的数;
选择
DFS(路径,选择列表)
回退选择
}
}
三、AC 代码:
N皇后的问题最重要的是选择条件的判断,要判断当前元素前面所有行里的当前列,左右对角线方向是否已经放置过,然后再遍历循环。
var solveNQueens = (n)=> {
let grid = new Array(n).fill(null).map(e=>new Array(n).fill('.'));
let res = [];
const hasQueen = (grid,i,j)=>{
for(let k=0;k<i;k++){
for(let m=0;m<n;m++){
if(grid[k][m]=='Q'&&(m==j||k+m==i+j||k-m==i-j)){
return false;
}
}
}
return true;
}
const DFS = (grid,i)=>{
if(i==n){
res.push(grid.slice().map(e=>e.join('')))
return;
}
for(let j=0;j<n;j++){
if(hasQueen(grid,i,j)){
grid[i][j] = 'Q';
DFS(grid,i+1,j);
grid[i][j] = '.'
}
}
}
DFS(grid,0)
return res;
};
四、总结:
回溯算法的场景非常的多,基本思想类似于图的深度优先搜索,二叉树的后序遍历,所以,有时候我们感觉就是深度优先遍历。 当问题是要求满足某种性质(约束条件)的所有解或最优解时,往往使用回溯法。
参考文档: