一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
一.题目:
51. N 皇后 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 <= n <= 9
二、思路分析:
这道题目跟我上篇文章的思路基本相同,都是利用回溯的思想进行全排列,只不过有一点不同的是,上篇文章要求不能是重复的数字,而这篇文章的要求是每个棋子上方,左上方,右上方,下方,左下方,右下方放置棋子,所以我们的解题步骤为:
- 先初始化棋盘全部初始化为
'.' - 我们的选择列表则是在每一行中选取一个位置放置棋子,然后进行判断是否是有效的放置
- 因为我们都是从上往下放置,所以我们只需要关注上方、左上方和右上方是否有棋子即可
- 在脱离一个决策后我们需要将这次选择的棋子从
'Q'重置为'.' - 在放置结果的时候需要注意对数组进行深拷贝并处理数据里面的数据即可完成作答
三、代码:
/**
* @param {number} n
* @return {string[][]}
*/
var solveNQueens = function(n) {
//还是利用回溯法进行求解
let board = new Array(n).fill('.').map((v) => new Array(n).fill('.'))
let res = []
const backtrack = function(board,row){
//终止条件
if(row == board.length){
let temp = JSON.parse(JSON.stringify(board))
for(let i = 0 ; i<n ; i++){
temp[i] = temp[i].join('')
}
res.push(temp)
return
}
for(let col = 0 ; col < n ; col++){
//排除不合法选择,上方,左上和右上
if(!isValid(board,row,col)) continue
//做选择
board[row][col] = 'Q'
//进入下一个决策
backtrack(board,row+1)
//撤销选择
board[row][col] = '.'
}
}
const isValid = function(board,row,col){
//检查上方
for(let i = 0 ; i < n ; i++){
if(board[i][col] == 'Q') return false
}
//检查左上
for(let i = row-1,j = col-1 ; i>=0&&j>=0 ; i--,j--){
if(board[i][j] == 'Q') return false
}
//检查右上
for(let i = row-1,j = col+1 ; i>=0&&j<n ; i--,j++){
if(board[i][j] == 'Q') return false
}
return true
}
backtrack(board,0)
return res
};
四、总结:
通过回溯方法进行全排列是个非常常规的套路,而
回溯法的思想也特别简单,我们只需要针对不同题目的要求修改特定区域的代码即可完成作答。