N皇后问题 leetcode --JavaScript(纪念第一次双百)

题目要求在这里插入图片描述点击查看原题

题目分析

观察上图可以知道要满足皇后之间彼此不能攻击需要满足下面四个条件
1:不在同一排
2:不在同一列
3:不在斜率为 1 的同一直线上(/)
4:不在斜率为 -1 的同一直线上(\)

因为是要找到所有摆放的情况,就要一个个位置试探着去摆放自然而然就会想到回溯法
一开始我计划用一个二维数组map 来存放皇后的摆放位置,和禁止摆放位置以n=4为例

 [
     ['Q','.','.','.'] // Q 代表皇后的位置 
     ['.','.','1','1'] // . 代表不能摆放的位置
     ['.','1','.','1'] // 1 代表能摆放的位置
     ['.','1','1','.']
 ]
 // 既然用到了标准位了,为什么不用二进制来表示呢?
 // 所以上面的map可以转换为==》
 [
     [1,0,0,0]  // 1 
     [0,0,1,1]  // 12
     [0,1,0,1]  // 10
     [0,1,1,0]  // 6
 ]   
 //1代表皇后的位置或者是可以放皇后的位置
// 将每个数组看做是一个4位的二进制数 转换为10进制数就是  ==>  
[1,12,10,6] // 这样我们就可以将原本的操作二维数组改成操作一维数组了。

上代码(解析在注释中)

var solveNQueens = function(n) {
  // 特殊值 1 的时候只有一个解 [['Q']]
  // n < 4 的时候无解(可以自己在纸上画一画)
  if (n === 1) {
    return [["Q"]];
  }
  let res = [];
  let max = Math.pow(2, n) - 1;
  for (let i = 0; i < n; i++) {
    // 初始化地图 例n = 4 =》 [15,15,15,15];
    // 循环填充第一排的皇后,在结果查找结构
    find(fillMap(new Array(n).fill(max), 0, i), 1);
  }
  return res;

  // 完成填充map的功能
  function fillMap(map, y, x) {
    let h = Math.pow(2, x);
    // 嚣张的一次性解决掉一排 比如将皇后放在第3个位置 =》 [0,0,1,0] = 4 
    map[y] = h;
    // i的初始值为y+1 ==> 即计算下一排需要置零的位置 不在同列和斜线上
    for (let i = y + 1; i < n; i++) {
      // 同列是必须要置零的
      let t = h;
      //   k = 1 ; ==》 根据公式y - yo = k(x-xo) 将x,y 和 k= 1代入可以计算出
      let positiveX = i - y + x;
      // 位置必须在地图内 即 0 < 计算的x < n
      if (positiveX >= 0 && positiveX < n) {
        t += Math.pow(2, positiveX);
      }
      //   k = -1  同 k = 1 
      let negativeX = x + y - i;
      if (negativeX < n && negativeX >= 0) {
        t += Math.pow(2, negativeX);
      }
      // t 相当于每个要置零的位置 max - t 相当于取反
      // 这里必须要用位操作,不能直接减 ,因为一个位置可能被多次置零。
      map[i] &= max - t;
    }
    return map;
  }

// 完成回溯查找的功能
  function find(map, y) {
   // 结束条件 如果填充到最后一排了要么是0 要么是 2^X 
    if (y === n - 1) {
      if (map[y] !== 0) {
        res.push(
        // 将一维数组转换为实际的结果
          map.map(item => {
            let x = Math.log2(item);
            return ".".repeat(x) + "Q" + ".".repeat(n - 1 - x);
          })
        );
      }
      return;
    }
    // 值不为0 代表这一排有可以放皇后的位置
    while (map[y] !== 0) {
       // 可以直接计算出可以放皇后的最高位,
      let x = Math.floor(Math.log2(map[y]));
      find(fillMap([...map], y, x), y + 1);
      // 只要一次查找完结,无论成功还是失败 都需要将这个位置置零开始下一次试探。
      map[y] -= Math.pow(2, x);
    }
    //如果某一排为0 代表这一排没有可以放皇后的位置试探结束
  }
};

实际跑出来的成绩

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值