LeetCode——51. N皇后

236 阅读2分钟

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

上图为 8 皇后问题的一种解法。

给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。

每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中'Q''.' 分别代表了皇后和空位。

示例:

输入: 4
输出: [
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。

回溯法

思路

N 皇后问题是对棋盘进行广度优先搜索,先确定每一层落子所在列,排除不可落子列。如果可行保留结果,同时清空选择,如果不可行回溯。

算法

  • 初始化三个集合,cols 用来存储列,pie 用来存储对角线常数,na 用来存储反对角线常数
  • 层层递进,排除不可行列,确定当前层落子所在列
  • 清空已经选择列

代码实现

/**
 * @param {number} n
 * @return {string[][]}
 */
var solveNQueens = function(n) {
  if (n < 1) return []
  let res = []
  // 存放列
  let cols = new Set()
  // 存放对角线常数
  let pie = new Set()
  // 存放反对角线常数
  let na = new Set()
  DFS(0, '')

  function DFS(row, cur_state) {
    // 递归结束条件
    // 如果行数大于等于n
    if (row >= n) {
      // 存结果
      res.push(cur_state)
      return
    }
    // 遍历所有可选择列 
    // 遍历当前行可以落子的所有可选择的列
    for (let col = 0; col < n; col++) {
      // 选择操作
      // 判断当前列如果不能落子,则结束本次循环
      if (cols.has(col) || pie.has(col + row) || na.has(col - row)) continue
      // 保存选择
      cols.add(col)
      pie.add(col + row)
      na.add(col - row)
      // 进入下一层
      DFS(row + 1, cur_state + col)
      // 清空选择
      cols.delete(col)
      pie.delete(col + row)
      na.delete(col - row)
    }
  }
  // 生成最终结果
  return res.map(item => item.split('').map(subItem => '.'.repeat(subItem) + 'Q' + '.'.repeat(n - subItem - 1)))
};