持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情
[面试题 08.12. 八皇后](leetcode.cn/problems/ha…)
设计一种算法,打印 N 皇后在 N × N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。
注意:本题相对原题做了扩展
「示例1:」
输入:4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释: 4 皇后问题存在如下两个不同的解法。
[ [".Q..", // 解法 1 "...Q", "Q...", "..Q."],
["..Q.", // 解法 2 "Q...", "...Q", ".Q.."]
]
解题思路
根据初高中知识点,判断两个二维空间点是否在对角线上,即y=-x或y=x直线上,也就是斜率=(y1-y2)/(x1-x2)等于1或者-1。这里用check()函数实现;
因此我们可以将已经放置了皇后的位置(x,y)记录下来,保存在diagonals数组中,判定某位置是否能够放置皇后,就将此位置与diagonals数组中的坐标一一验证比对是否构成对角线,只要与其中一个构成对角线,说明此位置不能放置皇后。
对角线的问题解决了,还有不同列不同行的问题,可以使用一维数组vis,长度为n,vis[i]=0,表示此i列位置没有被使用,反之表示被使用过了,这就解决了不同列的问题,因为我们用 X 递增查找的,能够直接避免同行的问题。
现在所有问题都有解决办法了,代码这可以写出来了
代码实现
var solveNQueens = function(n) {
let vis=new Array(n).fill(0);//初始化所有**列**的位置
let res=[],flag=[];
let diagonals=[];
for(let i=0;i<n;i++){
flag[i]=new Array(n).fill('.'); //用flag表示棋盘,这里是初始化棋盘
}
function NQueens(item,x){ //item和flag都表示棋盘,一个是形参,一个是实参
if(x==n){ //设置递归条件,同时x==n说明所有**行**都找到了放置皇后的位置
let temp=item.concat(); //避免浅拷贝问题
for(let i=0;i<temp.length;i++){
temp[i]=temp[i].join(''); //将数组["Q",".",".","."]转换为[Q...]
}
res.push(temp); //添加答案
return;
}
for(let i=0;i<n;i++){
if(vis[i]==0&&check(diagonals,x,i)){ //判断当前**列**位置是否被使用和此位置是否与之前的保存的皇后位置构成对角线
vis[i]=1; //将此 **列** 置为1,表示已经使用过了
diagonals.push([x,i]); //将放置过皇后的位置(x,y)记录下来
item[x][i]='Q'; //在棋盘位置放置皇后,也说明此**行**找到了皇后位置
NQueens(item,x+1) //递归,寻找下一**行**的皇后位置
vis[i]=0; //回溯
diagonals.pop(); //回溯
item[x][i]='.'; //回溯
}
}
}
NQueens(flag,0); //调用函数
return res;
};
function check(nums,x,y){ //判断某位置与之前保存的皇后位置是否构成对角线
for(let i=0;i<nums.length;i++){ // 判断(y1-y2)/(x1-x2) =1或-1
if(nums[i][0]-x==nums[i][1]-y||x-nums[i][0]==nums[i][1]-y){
return false;
}
}
return true;
}
如果你对这道题目还有疑问的话,可以在评论区进行留言;