/*
先来看问题,其实问题不难理解:
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],
["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。
思路
乍一看这种选出全部方案的问题有点难找到头绪,但是其实仔细看一下,题目已经限定了皇后之间不能互相攻击,转化成代码思维的语言其实就是说每一行只能有一个皇后,每条对角线上也只能有一个皇后,
也就是说:
在一列上,错。
[
‘Q’, 0
‘Q’, 0
]
复制代码
在左上 -> 右下的对角线上,错。
[
‘Q’, 0
0, ‘Q’
]
复制代码
在左下 -> 右上的对角线上,错。
[
0, ‘Q’
‘Q’, 0
]
那么以这个思路为基准,我们就可以把这个问题转化成一个「逐行放置皇后」的问题,思考一下递归函数应该怎么设计?
对于 n皇后 的求解,我们可以设计一个接受如下参数的函数:
实现
理想总是美好的,虽然目前为止我们的思路很清晰了,但是具体的编码还是会遇到几个头疼的问题的。
当前一行已经落下一个皇后之后,下一行需要判断三个条件:
直接通过这个点的纵横坐标rowIndex + columnIndex 相加,相等的话 就在同条对角线1上
对角线1:
2n-1个
i+j
直接通过这个点的横纵坐标 rowIndex - columnIndex 相减,相等的话 就在对角线2上
对角线2:
2*n - 1个
i - j + n - 1
所以:
1 用columns数据记录摆放的列下标 摆放后直接标记为true即可
2 用dia1数组记录摆放过的对角线1下标,摆放后直接把下标rowIndex + columnIndex标记为true即可
3 用dia2 数组记录摆放过的对角线2下标 摆放后直接把下标rowIndex - columnIndex 标记为true即可
4 递归函数 的参数prev代表每一行中皇后放置的列数,比如prev[0] = 3 代表第 0 行皇后放在第3列 以此类推
5 每次进入递归函数前 先把当前项对应的列 对角线1 对角线2 的下标标记为true,带着标记后的状态进入递归函数
并且在推出本次递归后 需要把这些状态重置为false 再进入下一轮循环
有了这几个辅助知识点 就可以开始编写递归函数了,在每一行 我们都不断的尝试一个坐标点,只要它和之前已有的结果不冲突 那么就可以放入数组中作为下一次递归的开始值
这样,如果递归函数顺利的来到了rowIndex === n 的情况 说明之前的条件全部满足了 一个n皇后的解就产生了 把prev这个一维数组通过辅助函数恢复成题目要求的二维数组即可
/**
* @param {number} n
* @return {string[][]}
*/
let solveNQueens = function(n){
let res = []
// 已经摆放皇后的列下标
let columns = []
// 已摆放皇后的对角线1下标 左下 ——> 右上
// 计算某个坐标是否在这个对角线的方式是 [行下标 + 列下标] 是否相等
let dia1 = []
// 已摆放皇后的对角线2下标 左上 -> 右下
// 计算某个坐标是否在这个对角线的方式是[行下标 - 列下标] 是否相等
let dia2 = []
// 在选择当前的格子后 记录状态
let record = (rowIndex,columnIndex,bool)=>{
columns[columnIndex] = bool
dia1[rowIndex + columnIndex] = bool
dia2[rowIndex - columnIndex] = bool
}
// 尝试在一个n皇后问题中 摆放第index行内的皇后位置
let putQueen = (rowIndex,prev)=>{
if(rowIndex === n){
res.push(generateBoard(prev))
return
}
// 尝试摆放第Index行的皇后 尝试[0,n-1]列
for(let columnIndex = 0; columnIndex
你可能感兴趣的:(算法,数据结构)