1. /**
  2. * @param {number} n
  3. * @return {string[][]}
  4. */
  5. let solveNQueens = function (n) {
  6. let res = []
  7. // 已摆放皇后的的列下标
  8. let columns = []
  9. // 已摆放皇后的对角线1下标 左下 -> 右上
  10. // 计算某个坐标是否在这个对角线的方式是「行下标 + 列下标」是否相等
  11. let dia1 = []
  12. // 已摆放皇后的对角线2下标 左上 -> 右下
  13. // 计算某个坐标是否在这个对角线的方式是「行下标 - 列下标」是否相等
  14. let dia2 = []
  15. // 在选择当前的格子后 记录状态
  16. let record = (rowIndex, columnIndex, bool) => {
  17. columns[columnIndex] = bool
  18. dia1[rowIndex + columnIndex] = bool
  19. dia2[rowIndex - columnIndex] = bool
  20. }
  21. // 尝试在一个n皇后问题中 摆放第index行内的皇后位置
  22. let putQueen = (rowIndex, prev) => {
  23. if (rowIndex === n) {
  24. res.push(generateBoard(prev))
  25. return
  26. }
  27. // 尝试摆第index行的皇后 尝试[0, n-1]列
  28. for (let columnIndex = 0; columnIndex < n; columnIndex++) {
  29. // 在列上不冲突
  30. let columnNotConflict = !columns[columnIndex]
  31. // 在对角线1上不冲突
  32. let dia1NotConflict = !dia1[rowIndex + columnIndex]
  33. // 在对角线2上不冲突
  34. let dia2NotConflict = !dia2[rowIndex - columnIndex]
  35. if (columnNotConflict && dia1NotConflict && dia2NotConflict) {
  36. // 都不冲突的话,先记录当前已选位置,进入下一轮递归
  37. record(rowIndex, columnIndex, true)
  38. putQueen(rowIndex + 1, prev.concat(columnIndex))
  39. // 递归出栈后,在状态中清除这个位置的记录,下一轮循环应该是一个全新的开始。
  40. record(rowIndex, columnIndex, false)
  41. }
  42. }
  43. }
  44. putQueen(0, [])
  45. return res
  46. }
  47. // 生成二维数组的辅助函数
  48. function generateBoard(row) {
  49. let n = row.length
  50. let res = []
  51. for (let y = 0; y < n; y++) {
  52. let cur = ""
  53. for (let x = 0; x < n; x++) {
  54. if (x === row[y]) {
  55. cur += "Q"
  56. } else {
  57. cur += "."
  58. }
  59. }
  60. res.push(cur)
  61. }
  62. return res
  63. }
  64. solveNQueens(4)
  65. //输出结果 [[".Q..", "...Q", "Q...", "..Q."], ["..Q.", "Q...", "...Q", ".Q.."]]

参考

前端「N皇后」递归回溯经典问题图解,面试难倒无数前端的经典问题。
前端玩转位运算(N皇后+Vue3位运算应用)