leetcode算法题之N皇后

N皇后也是一道很经典的问题,问题如下:

题目地址

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

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

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

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

解法:回溯

回溯是基于 DFS 的一种算法,它通过在解空间树中深度探索并尝试所有可能的解来解决问题。当发现当前路径无法满足问题的约束条件时,算法会“回溯”到上一步,尝试另一条路径

首先我们先建立一个二维数组,方便我们在回溯时直接更改对应的状态

const dp = new Array(n).fill(0).map(() => new Array(n).fill("."));

由当前问题我们可得知棋盘的每行必定要放置一个皇后,不然不会有满足题目的解,所以可以把每一列当作一层,把皇后放置后再到下一层继续放置,基本代码如下

const backtrack = (line) => {
  // 遍历每一行,放置皇后
  for (let i = 0; i < n; i++) {
    dp[line][i] = "Q";
    backtrack(line + 1)
    // 回溯的核心,当我们使用完后一定要将状态恢复,不然会影响下一个结果
    dp[line][i] = ".";
  }
}

backtrack(0);

接下来的问题就是我们要怎么判断当前位置可不可以放置皇后,有的童鞋可能想着所有方向都遍历一下,其实不用这么麻烦,因为我们是由上往下放置,所以只需要判断左上,上,右上的方向就可以啦

// 检测位置是否可以放皇后
const checkPosition = (x, y) => {
  // 检测上方
  let tx = x;
  while (--tx > -1) {
    if (dp[tx][y] === "Q") {
      return false;
    }
  }
  // 检测上斜左
  let lx = x,
    ly = y;
  while (--lx > -1 && --ly > -1) {
    if (dp[lx][ly] === "Q") {
      return false;
    }
  }
  // 检测上斜右
  let rx = x,
    ry = y;
  while (--rx > -1 && ++ry < n) {
    if (dp[rx][ry] === "Q") {
      return false;
    }
  }
  return true;
};

既然说到回溯,那肯定涉及到剪枝问题了,其实也不用做啥,当我们发现某一行无法放置任何皇后时,我们什么都不做,直接回溯到上一行即可

完整代码如下:

/**
 * @param {number} n
 * @return {string[][]}
 */
var solveNQueens = function (n) {
  let dp = new Array(n).fill(0).map(() => new Array(n).fill("."));
  const result = [];
  let queenNum = n;

  // 检测位置是否可以放皇后
  const checkPosition = (x, y) => {
    // 检测上方
    let tx = x;
    while (--tx > -1) {
      if (dp[tx][y] === "Q") {
        return false;
      }
    }
    // 检测上斜左
    let lx = x,
      ly = y;
    while (--lx > -1 && --ly > -1) {
      if (dp[lx][ly] === "Q") {
        return false;
      }
    }
    // 检测上斜右
    let rx = x,
      ry = y;
    while (--rx > -1 && ++ry < n) {
      if (dp[rx][ry] === "Q") {
        return false;
      }
    }
    return true;
  };
  const pushResult = () => {
    let newDp = [];
    for (let i = 0; i < n; i++) {
      newDp[i] = dp[i].join("");
    }
    result.push(newDp);
  };
  const backtrack = (line) => {
    if (line === n) {
      pushResult();
      return;
    }
    for (let i = 0; i < n; i++) {
      // 判断是否可以放置皇后
      if (line === 0 || (line > 0 && checkPosition(line, i))) {
        dp[line][i] = "Q";
        backtrack(line + 1);
        dp[line][i] = ".";
      }
    }
  };
  backtrack(0);
  return result;
};

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值