N皇后问题详解

article/2025/10/6 3:39:38

文章目录

    • 一、题目描述
    • 二、题目解析
      • (1)思考一(集合+回溯)
      • (2)思考二(数组+深度递归)
      • (3)思考三(位运算)

一、题目描述

N 皇后问题是指在 n * n 的棋盘上要摆 n 个皇后,
要求:任何两个皇后不同行不同列不在同一条斜线上,
求给一个整数 n ,返回 n 皇后的摆法数。

数据范围: 1 ≤ n ≤ 9

例如当输入4时,对应的返回值为2,对应的两种四皇后摆位如下图所示:

在这里插入图片描述

二、题目解析

(1)思考一(集合+回溯)

变量罗列:

  • i:行号
  • j:列号
  • set1:保存已经被占用的列
  • set2:保存已经被占用的左斜线(横纵坐标相加确定一条左斜线)
  • set3:保存已经被占用的右斜线(横纵坐标相减确定一条右斜线)
  • result :摆放数

思路分析:

将从第 0 行开始放皇后,放成功后再放第 1 行,保证皇后们都不在同一行上

在第 i 行寻找放皇后的位置时,将会依次从第 0 列尝试到第 n-1 列,尝试着将皇后放在坐标 (i,j)上,如果 set1 中没有包含 j,set2 中没有包含 i+j,set3 中没有包含 i-j,皇后放置成功

第 i 行的皇后放成功后,就可以开始放第 i+1 行的皇后,直到 i == n ,棋盘上成功多出了一种摆放法,result 加一

返回后就回溯,撤掉刚才摆放好的皇后,尝试下一列,没有下一列说明当前方法执行完毕,返回了

代码展示:

public class Solution {public HashSet<Integer> set1 = new HashSet<>();//列public HashSet<Integer> set2 = new HashSet<>();//正斜线public HashSet<Integer> set3 = new HashSet<>();//反斜线public int result = 0;public int Nqueen (int n) {func(0,n);//表示从第0行开始放,一共有n行return result;}public void func(int i,int n) {if(i == n) {//放好了result++;return;}//在第i行中依次找到一个合适的列放皇后for(int j = 0;j < n;j ++) {if(set1.contains(j) || set2.contains(i+j) || set3.contains(i-j)) {continue;//都是不符合条件的}set1.add(j);set2.add(i+j);set3.add(i-j);//放好了,尝试下一行func(i+1,n);//恢复原样set1.remove(j);set2.remove(i+j);set3.remove(i-j);}}
}

(2)思考二(数组+深度递归)

变量罗列:

  • i:行号
  • j:列号
  • board数组:board[i] 表示第 i 行放皇后的列号
  • result :摆放数

思路分析:

和思路一的区别在于使用一个数组代替三个 set 集合

在第 i 行放置皇后时,第 0 行到第 i-1 行都放好皇后,board[0~i-1] 上的值都有效,符合题目的限定条件

在判断坐标(i,j)位置是否能够放皇后时,如果board[k] (0 ≤ k ≤ i-1) 的值等于 j ,说明和第 k 行的皇后重行。如果 board[k] 和 j 差的绝对值等于 k 和 i 差的绝对值,说明坐标 (i,j)和坐标(k,board[k])相连后和水平呈45度角,即在同一条斜线上(包含左斜线和右斜线)

将第 i 行上所有可以放置皇后的列所包含的摆法数累加,并返回

代码展示:

public class Solution1 {public int Nqueen (int n) {int[] board = new int[n];//表示棋盘//board[i]表示第i行放皇后的列,board[2] = 3 表示第二行的皇后放在了第3列上return func(0,board,n);//表示从第0行开始往下摆皇后}public int func(int i,int[] board,int n) {//准备开始摆第i行的皇后//此时board[0~i-1]都已经有了有效值,即0~i-1行上都符合规则的放好了皇后if(i == n) {//到达终止行,即棋盘最后一行也摆好了皇后return 1;}int result = 0;//对第i行上所有符合条件可以放皇后的列的方法数进行累加for(int j = 0;j < n;j ++) {if(isOK(board,i,j)) {//可以放皇后,深度递归board[i] = j;result += func(i+1,board,n);}}return result;}//就是来验证第i行第j列是否能放皇后public boolean isOK(int[] board,int i,int j) {for(int k = 0;k < i;k ++) {if(board[k] == j || Math.abs(board[k]-j) == Math.abs(k-i)) {return false;//不符合条件}}return true;}
}

(3)思考三(位运算)

以上两种方法的时间复杂度都是 O(n!) ,空间复杂度为 O(n),指标已经是没有办法优化了,但是可以通过位运算进行常数时间的优化,优化的目的就是省去依次判断和过去放过的皇后有重列或者重斜线的步骤

变量罗列:

  • limit:表示位的限制,该值的后 n 位为 1 (若为7皇后,limit为0… 0111 1111)
  • colLim:表示列的限制,1表示已经放了皇后,0表示没有放过皇后
  • leftLim:表示左斜线的限制,1表示已经放了皇后,0表示没有放过皇后
  • rightLim:表示右斜线的限制,1表示已经放了皇后,0表示没有放过皇后
  • pos:可以放皇后的位置,1表示可以放皇后,0表示不能放皇后
  • lastOneIndex:pos最右侧的1的权值

思路分析:

以 8 皇后进行举例:

如果 colLim 后 8 位都是 1(等于limit),说明棋盘上所有的列都放上了皇后,摆放数加一

假设第 0 行的皇后放在了第 5 列

在这里插入图片描述

此时的 pos 值有 5 个 1,代表只有这 5 列还可以放皇后,通过 pos & (~pos + 1) 就可以求的最右侧的 1的权值(lastOneIndex),将皇后放到此处,pos 减去权值,直到 pos 为 0 说明 5 个放皇后的地方都尝试过了,累加摆放数

在这里插入图片描述

在这里插入图片描述

代码展示:

public class Solution2 {//限制:只能是1~32皇后public int Nqueen (int n) {// write code hereif (n < 1 || n > 32) {return -1;}//如果是8皇后,limit该值的后8位为1,之后所有的限制就都限制在了后8位上int limit = (n == 32 ? -1 : (1 << n) - 1);//colLim表示列的限制,leftLim表示左斜线的限制,rightLim表示右斜线的限制//1表示已经放了皇后,0表示还没有放皇后return func(limit,0,0,0);}public int func(int limit,int colLim,int leftLim,int rightLim) {if (colLim == limit) {//所有的列上都放了皇后return 1;}int result = 0;//找到可以放皇后的位置(此时1的位置可以放皇后,0的位置不能放皇后)int pos = limit & (~(colLim | leftLim | rightLim));int lastOneIndex = 0;//表示pos的最右侧的1(可以放皇后的位置)while (pos != 0) {lastOneIndex = pos & (~pos + 1);pos -= lastOneIndex;//该位置已经被放皇后,去除result += func(limit,colLim | lastOneIndex,(leftLim | lastOneIndex) << 1,(rightLim | lastOneIndex) >>>1);}return  result;}
}

http://chatgpt.dhexx.cn/article/n1W0OsIZ.shtml

相关文章

3.2 回溯法—N皇后问题

1. 问题描述 在 n n n\times n nn的棋盘上摆放 n n n个皇后&#xff0c;使任意两个皇后都不能处于同一行、同一列或同一斜线上 2. 问题分析 下以求解4皇后问题为例&#xff0c;分析4皇后问题的排列树以及回溯过程&#xff1a; 搜索及回溯过程&#xff1a; 解空间树&#…

【经典算法】N皇后问题

✨前言✨ N皇后问题经典的解决方案是暴力递归&#xff0c;其时间复杂度是O(2^n),因此常用来测试计算机的算力。今天我会给大家带来经典方法的详解&#xff0c;也会给大家展示N皇后优化后的大神解法。做一道经典题目&#xff0c;来一场思维旅行。 目录 ✨前言✨ &#x1f4a1;…

n皇后问题(回溯法)(超易理解)(详细注释)

问题&#xff1a; N皇后问题是一个经典的问题&#xff0c;描述如下&#xff1a; 在的方格棋盘需要放置N个皇后&#xff0c;使得它们不相互攻击&#xff0c; 即任意2个皇后不允许处在同一排&#xff0c;同一列&#xff0c;也不允许处在与棋盘边框成45度角的斜线上。 对于给定的N…

n皇后问题(回溯法)

目录 1.问题描述 2.问题分析 3.完整源码 1.问题描述 八皇后问题是十九世纪著名的数学家高斯于1850年提出的。问题是:在88的棋盘上摆放八个皇后&#xff0c;使其不能互相攻击&#xff0c;即任意两个皇后都不能处于同一行、同一列或同一斜线上。可以把八皇后问题扩展到n皇后问…

【浏览器跨域】跨域访问接口浏览器怎么设置?

window系统 1、右键浏览器&#xff0c;点击属性 2、找到目标&#xff0c;目标输入框内容最后面加上 --disable-web-security --user-data-dirC:\MyChromeDevUserData&#xff0c;–user-data-dir 3、点击确定 4、重新打开浏览器即可 mac系统 终端输入&#xff0c;重新打开浏…

AJAX跨域访问(不同域之间相互访问)

目录 一、跨域&#xff1a;二、同源策略&#xff1a;三、解决Ajax跨域问题的方案&#xff1a;方案一&#xff1a;设置响应头方案二&#xff1a;jsonp方案三&#xff1a;jQuery封装jsonp方案四&#xff1a;代理机制&#xff08;httpclient&#xff09;方案五&#xff1a;nginx反…

nginx配置图片跨域访问

在server段中添加红框内的图片跨域内容 参数 location ~* .*.(gif|jpg|jpeg|png|bmp|swf)$ { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers X-Requested-With; add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS…

浏览器跨域访问限制

一.什么是跨域 广义的跨域&#xff1a; (1) 资源跳转&#xff1a;A链接、重定向、表单提交 (2) 资源嵌入&#xff1a;<link>、<script>、<img>、<frame>等dom标签&#xff0c;还有样式中background:url()、font-face()等文件外链 (3) 脚本请求&#x…

Django 多方式实现跨域访问

一、什么是跨域 1.1 跨越介绍 跨域&#xff0c;是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的&#xff0c;是浏览器对JavaScript实施的安全限制。 这里说明一下&#xff0c;无法跨域是浏览器对于用户安全的考虑&#xff0c;如果自己写个没有同源策略的浏览…

Flask中跨域访问的实现

在我们访问不同的服务器时&#xff0c;就会涉及到了跨域的问题。因为不同域名之间是无法进行交流的&#xff0c;然后跨域就打破了这种规则的限制。说起Flask中的跨域&#xff0c;就不得不提到CORS组件了&#xff0c;相信大家在其它框架中也见过了它的身影。下面我们就跨域问题和…

Tomcat设置允许跨域访问

开发React项目时前端通过axios向后端代码发起请求调试的时候由于后端代码运行在8080端口而React项目运行在3000端口导致浏览器的同源策略禁止跨域请求&#xff0c;因此需修改Tomcat配置文件web.xml以开放跨域访问。 在tomcat的web.xml文件末尾加上&#xff1a; <filter>…

express 允许跨域访问

设置Express const express require(express) const bodyParser require(body-parser)const app express() // 处理参数 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false }));// 设置允许跨域访问该服务 app.all(*, function (req, res, nex…

tomcat 设置允许跨域访问

既然想到使用tomcat进行跨域的设置&#xff0c;而不使用在项目中设置header来解决&#xff0c;说明你也是tomcat 下的资源需要做跨域处理吧&#xff1f;这也是一个统一的允许跨域设置&#xff0c;tomcat下的所有请求都将放开&#xff0c;请注意。 具体步骤&#xff1a; 1.首先…

Chrome浏览器 设置跨域访问

由于浏览器的安全策略&#xff0c;不同域名的访问会被限制&#xff0c;导致不能访问 chorme或者360都可以使用下列设置来解决这个问题&#xff1a; &#xff08;1&#xff09;在电脑上新建一个目录&#xff0c;例如&#xff1a;C:\MyChromeEnvUserData &#xff08;2&#x…

tomcat9配置允许跨域访问

目录 一、问题描述二、解决办法三、程序截图 一、问题描述 最近在用Tomcat9最新版本部署程序的时候&#xff0c;发现其他服务访问我的静态资源的时候出现了跨域访问&#xff0c;结果很明显被拦截了&#xff0c;之前的文章介绍了Tomcat8.5的跨域配置&#xff0c;但是研究发现&a…

html的页面怎样直接跨域访问,【HTML】iframe跨域访问问题

概述 本地同一浏览器访问本地HTML文件和访问服务器端HTML文件,本地Iframe没有自适应高度,而服务器端的Ifrane自适应了高度。 1.问题重现: Chrome 版本 41.0.2272.101 (64-bit) OS:Win8.1 Chrome访问服务器端HTML文件呈现的结果 Chrome访问本地HTML文件呈现的结果 本地访问的…

vue跨域访问

vue跨域访问的问题&#xff08;基于允许跨域访问的前提&#xff09; 找到“ vue.config.js"&#xff0c;有些不是vue.config.js命名&#xff0c;也就是找到重写路径的js文件。重写一下自己要替换的路径&#xff0c;在原有基础上加一个 新建一个dev.js文件内容如下&#…

关于跨域访问

1 概念 2 案例 3 解决 4 实现 5 什么是跨域问题 示意图 1 概念 跨域访问&#xff0c;是指从一个域名的网页去请求另一个域名的资源。比如从 www.baidu.com 页面去请求 ww w.google.com 的资源。 但是一般情况下不能这么做跨域访问&#xff0c;因为有浏览器的 “ 同源策略…

什么是跨域?如何实现跨域访问?

跨域是指不同域名之间相互访问。 JavaScript同源策略的限制&#xff0c;A域名下的JavaScript无法操作B或是C域名下的对象 实现&#xff1a; 1、JSONP跨域&#xff1a;利用script脚本允许引用不同域下的js实现的&#xff0c;将回调方法带入服务器&#xff0c;返回结果时回调 2、…

跨域访问

跨域访问是什么 同源策略 1995年&#xff0c;同源政策由Netscape公司引人浏览器。目前&#xff0c;所有刘览器都实行这个政策。同源政策的目的&#xff0c;是为了保证用户信息的安全&#xff0c;防止恶意的网站窃取数据。随着互联网的发展&#xff0c;“同源政策”越来越严格…