N皇后问题

239 阅读2分钟

题目

N皇后问题是指在N*N的棋盘.上要摆N个皇后,要求任何两个皇后不同行、不同列,也不在同一条斜线上。 给定一个整数n,返回N皇后的摆法有多少种。n=1,返回1。n=2或3,2皇后和3皇后问题无论怎么摆都不行,返回0。n=8,返回92。

  • n*n的棋盘,要放n个皇后,注意皇后的个数是要和棋盘行数相同的
  • n*n的棋盘要放n个皇后,并且还必须不同列不同行不同对角线,所以每个皇后必须分散在每一行(列)才有可能
    • 要遍历出每一种结果,即从第一行第一列开始放一个皇后,然后采取按行深度遍历,从第二行放置符合条件的皇后,同理从第三行、第四行找符合条件的皇后,为了减少遍历次数(动态规划),只有当前行符合才继续去下一行找(需要记录符合的历史节点),第一行第一列遍历结束后,接着从第一行第二列重复这样的过程,最终第一行最后一列遍历结束时,就能统计出所有结果
function NQueen(n) {
  let line = 0, //当前遍历到的行数
    records = [], // 已经记录到的可以摆放的皇后位置,a[0]=2,表示第一行第三列
    res = 0;

  if (n < 1) {
    return 0;
  }

  function getN(line, n, records) {
    if (line === n) {
      //当已经遍历完所有的行,
      res++;
    }

    for (let j = 0; j < n; j++) {
      // 只会和在当前行之前的行所记录的点判断,且是从上到下的深度遍历,上次对应行记录的数会被当前满足的点覆盖掉
      // 比如假设上次记录的是a[0]=b0,a[1]=b1,a[2]=b2,a[3]=b3
      // 在重新开始从第一行记录时,因为只比较前面的行,所以a[0]会被重写,同理a[1]某个点满足时也会重写a[1]
      // 所以之前records记录不用清除
      if (isValid(line, j, records)) {
        records[line] = j;
        getN(line + 1, n, records);
      }
    }
  }
  // 判断和之前的皇后不同列、不同对角线
  function isValid(line, j, records) {
    for (let i = 0; i < line; i++) {
      if (records[i] == j || Math.abs(records[i] - j) == Math.abs(i - line)) {
        return false;
      }
    }
    return true;
  }

  getN(line, n, records);

  return res;
}

console.log(NQueen(4));