解锁棋盘之谜:探索N皇后问题的全方位解决策略【python 力扣51题】

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
欢迎加入社区:码上找工作
作者专栏每日更新:
LeetCode解锁1000题: 打怪升级之旅
python数据分析可视化:企业实战案例
备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

题目描述

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

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

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

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
示例 1:
在这里插入图片描述
输入格式

  • n:一个整数,表示棋盘的大小(即棋盘有 n 行和 n 列)。

输出格式

  • 返回所有独特的 n 皇后问题的解决方案。
输入: n = 4
输出: [["..Q.",  // 解法 1"Q...","...Q",".Q.."],["Q...",  // 解法 2"..Q.","Q...","...Q"]
]

示例 2:

输入:n = 1
输出:[["Q"]]

方法一:回溯算法

解题步骤
  1. 初始化:创建一个 n×n 的棋盘,开始时每个位置都是空的 '.'
  2. 回溯函数:使用递归函数 backtrack 来试探每一行的每一个位置,检查放置皇后是否合法。
  3. 合法性检查:为每个皇后的位置进行合法性检查,确保没有两个皇后能攻击到对方。
  4. 递归与回溯:递归地放置下一个皇后,如果当前放置不合法则回溯(撤销上一步的操作)。
完整的规范代码
def solveNQueens(n):def backtrack(row, diagonals, anti_diagonals, cols, state):# Base case - a valid solution is foundif row == n:board = build_board(state)solutions.append(board)returnfor col in range(n):curr_diagonal = row - colcurr_anti_diagonal = row + col# If the queen is not placeableif (col in cols or curr_diagonal in diagonals or curr_anti_diagonal in anti_diagonals):continue# "Add" queen to the boardcols.add(col)diagonals.add(curr_diagonal)anti_diagonals.add(curr_anti_diagonal)state.append(col)# Move on to the next row with the updated statebacktrack(row + 1, diagonals, anti_diagonals, cols, state)# "Remove" queen from the board (backtrack)cols.remove(col)diagonals.remove(curr_diagonal)anti_diagonals.remove(curr_anti_diagonal)state.pop()def build_board(state):board = []for i in range(n):row = ['.' for _ in range(n)]row[state[i]] = 'Q'board.append(''.join(row))return boardsolutions = []backtrack(0, set(), set(), set(), [])return solutions# 示例调用
print(solveNQueens(4))
算法分析
  • 时间复杂度:(O(n!)),每层递归减少的选择数大约是 n,因此时间复杂度接近于 n!
  • 空间复杂度:(O(n)),主要消耗在递归栈上。

方法二:位运算优化的回溯算法

解题步骤
  1. 利用位运算:使用整数的位来代表棋盘上的列和对角线的占用情况,通过位运算来快速检查和修改状态。
  2. 优化回溯:通过位运算加速合法位置的检查过程,使用位掩码来控制递归过程。
完整的规范代码
def solveNQueens(n):def backtrack(row, cols, diag1, diag2, state):if row == n:board = build_board(state)solutions.append(board)returnavailable_positions = (~(cols | diag1 | diag2)) & ((1 << n) - 1)while available_positions:position = available_positions & -available_positionscol = bin(position).count('0') - 1state.append(col)backtrack(row + 1, cols | position, (diag1 | position) << 1, (diag2 | position) >> 1, state)state.pop()available_positions &= available_positions - 1def build_board(state):board = []for i in range(n):row = ['.' for _ in range(n)]row[state[i]] = 'Q'board.append(''.join(row))return boardsolutions = []backtrack(0, 0, 0, 0, [])return solutions# 示例调用
print(solveNQueens(4))
算法分析
  • 时间复杂度:(O(n!)),尽管实际上比普通的回溯要快,因为位运算提供了更快的速度。
  • 空间复杂度:(O(n)),空间消耗主要在递归栈上。

方法三:基于列和对角线的回溯

解题步骤
  1. 标记法:使用三个标记数组,分别记录列和两个方向的对角线的占用情况。
  2. 简化检查:通过标记数组,简化每次放置皇后时的合法性检查。
完整的规范代码
def solveNQueens(n):def backtrack(row):if row == n:solutions.append(["".join(row) for row in board])returnfor col in range(n):if not (cols[col] or diag1[row + col] or diag2[row - col + n - 1]):board[row][col] = 'Q'cols[col] = diag1[row + col] = diag2[row - col + n - 1] = Truebacktrack(row + 1)board[row][col] = '.'cols[col] = diag1[row + col] = diag2[row - col + n - 1] = Falseboard = [["."]*n for _ in range(n)]cols = [False]*ndiag1 = [False]*(2*n-1)diag2 = [False]*(2*n-1)solutions = []backtrack(0)return solutions# 示例调用
print(solveNQueens(4))
算法分析
  • 时间复杂度:(O(n!)),对于每一行,逐个检查每列是否可以放置皇后。
  • 空间复杂度:(O(n)),需要额外空间来存储棋盘状态及递归栈。

方法四:DFS优化标记

解题步骤
  1. 深度优先搜索:使用深度优先搜索遍历所有可能的棋盘配置。
  2. 优化标记:使用一维数组存储棋盘状态,通过索引和值的关系减少空间复杂度。
完整的规范代码
def solveNQueens(n):def dfs(queens, xy_diff, xy_sum):p = len(queens)if p==n:result.append(queens)return Nonefor q in range(n):if q not in queens and p-q not in xy_diff and p+q not in xy_sum: dfs(queens+[q], xy_diff+[p-q], xy_sum+[p+q])result = []dfs([], [], [])return [ ["."*i + "Q" + "."*(n-i-1) for i in sol] for sol in result]# 示例调用
print(solveNQueens(4))
算法分析
  • 时间复杂度:(O(n!)),尽管通过优化减少了不必要的检查。
  • 空间复杂度:(O(n)),递归深度决定了空间复杂度。

方法五:迭代回溯

解题步骤
  1. 迭代回溯:使用栈来模拟递归过程,避免函数调用的开销。
  2. 状态管理:显式地在迭代中管理棋盘状态和递归变量。
完整的规范代码
def solveNQueens(n):stack = [(0, [], [], [])]  # (row, queens, xy_diff, xy_sum)results = []while stack:row, queens, xy_diff, xy_sum = stack.pop()if row == n:board = build_board(queens)results.append(board)else:for col in range(n):if col not in queens and row - col not in xy_diff and row + col not in xy_sum:stack.append((row + 1, queens + [col], xy_diff + [row - col], xy_sum + [row + col]))return resultsdef build_board(queens):n = len(queens)board = []for i in queens:board.append('.' * i + 'Q' + '.' * (n - i - 1))return board# 示例调用
print(solveNQueens(4))
算法分析
  • 时间复杂度:(O(n!)),尽管迭代可能减少了一些函数调用开销。
  • 空间复杂度:(O(n)),主要由栈的深度决定。

不同算法的优劣势对比

特征方法一: 回溯算法方法二: 位运算优化回溯方法三: 基于标记的回溯方法四: DFS优化标记方法五: 迭代回溯
时间复杂度(O(n!))(O(n!))(O(n!))(O(n!))(O(n!))
空间复杂度(O(n))(O(n))(O(n))(O(n))(O(n))
优势- 易于理解和实现- 空间效率高- 易于调试和实现- 空间利用最优化- 避免递归,减少调用开销
劣势- 空间消耗较大- 理解和实现复杂- 状态管理较为复杂- 实现较为复杂- 状态维护复杂

应用示例

算法竞赛和面试
在算法竞赛和技术面试中,N皇后问题是一类常见的问题,用于测试候选人的递归思维和问题解决能力。掌握多种解决方法可以在不同的面试环境中灵活应对。

教育和研究
N皇后问题在算法教学和计算机科学研究中有广泛应用,常作为回溯算法和递归思想的示例问题。通过这个问题,可以深入理解递归、回溯以及剪枝等概念。

这些算法及其对比提供了一个全面的视角来理解和应用不同的编程技巧和优化方法,适用于解决实际问题并优化现有解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/1128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QML 中引用 js 文件闪退问题

问题描述 在移植 Android 中遇到这样一个引用兼容性问题&#xff0c;起因是这样的&#xff0c;Windows 版本的采用了 QML 分离的方式加载&#xff0c;而 Android 版本又采用了 qrc 的方式。而 Qt 中的机制是采用 QML 分离方式时则使用相对路径的方式引用 js 文件&#xff0c;而…

ZCMU 1531: 序列的混乱程度

Description 有一个长度为n的正整数序列&#xff0c;一个序列的混乱程度定义为这个序列的最大值和最小值之差。请编写一个程序&#xff0c;计算一个序列的混乱程度。 Input 输入的第一行为一个正整数T (T<1000)&#xff0c;表示一共有T组测试数据。 每组测试数据的第一行为一…

前后端跨域请求代码实战(vue3.4+springboot2.7.18)

前端代码 v3.4.21&#xff08;前端不是主业&#xff0c;所以就贴一贴代码&#xff0c;有疑问评论区见&#xff09;后端代码&#xff0c;springboot 2.7.18&#xff08;后端&#xff09; 文章内容&#xff1a; 一&#xff0c;后端代码 二&#xff0c;前端代码 三&#xff0c;后…

【ARM 裸机】I.MX 启动方式之启动头文件 1

接上一节&#xff1a;【ARM 裸机】I.MX 启动方式之启动设备的选择&#xff1b; 2、启动头文件 当 BOOT_MODE1 为 1&#xff0c;BOOT_MODE0 为 0 的时候此内部 BOOT 模式&#xff0c;在此模式下&#xff0c;芯片会执 行内部的 BOOT ROM 代码&#xff0c;这段 BOOT ROM 代码会进…

C++引用和指针的区别

在C中&#xff0c;引用和指针都是用于间接访问变量或对象的工具&#xff0c;但它们之间存在一些重要的区别。 引用&#xff08;Reference&#xff09; 引用是变量的别名&#xff0c;它提供了一个已经存在的变量的另一个名字。一旦一个引用被初始化为一个对象&#xff0c;就不…

tensor是pytorch的核心,那torch.tensor和torch.Tensor区别是?

本文重点 从本节课程开始我们将正式开启pytorch的学习了&#xff0c;在深度学习框架中有一个重要的概念叫做张量&#xff0c;它是pytorch的基本操作单位&#xff0c;要想创建tensor有很多的方式&#xff0c;但是有两个torch.tensor和torch.Tensor容易混淆&#xff0c;本节课程…

javase__进阶 day13stream流和方法引用

1.不可变集合 1.1 什么是不可变集合 ​ 是一个长度不可变&#xff0c;内容也无法修改的集合 1.2 使用场景 ​ 如果某个数据不能被修改&#xff0c;把它防御性地拷贝到不可变集合中是个很好的实践。 ​ 当集合对象被不可信的库调用时&#xff0c;不可变形式是安全的。 简单…

docker快速使用简介

进入服务器 ssh root192.0.0.211安装 docker load < bevformer_image.tar修改镜像的REPOSITORY和TAG docker tag a6a4c15ca9db bevformer:1.0其中&#xff0c;a6a4c15ca9db是原来镜像的id。bevformer是修改后的REPOSITORY&#xff1b;1.0是修改后的TAG。 从Docker Hub上…

高精度加减乘除

高精度加法 题目链接&#xff1a;高精度加法 #include <bits/stdc.h> #define int long long using namespace std; const int N 1e55; int a[N],b[N]; int c[N]; int n,m; string s1,s2;signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>s1…

大厂面试精华面试刷题

1.自定义unshift实现相同效果 2.数组去重 用vs2019来写这种练习题可以更直观的查看代码执行的效果&#xff0c;最后的代码是控制控制台执行完毕后不自动关闭 use strict;let arr [1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10] //1.//查重最简单的方法for循环结合splice从数组中…

Flask vs FastApi 性能对比测试

Flask和Fastapi都是Python下流行的Web框架&#xff0c;前者有大量拥趸&#xff0c;是一个老牌框架&#xff0c;后者相对较新&#xff0c;但是利用了异步技术和uvloop&#xff0c;都说性能比Flask好很多&#xff0c;于是就我就对比实测一下。由于Windows下不支持uvloop&#xff…

63、ARM/STM32中IIC相关学习20240417

完成温湿度传感器数据采集实验。 【思路&#xff1a;1.通过IIC通信原理&#xff0c;理解其通信过程&#xff0c;通过调用封装的IIC函数达成主机和从机之间&#xff1a;起始信号、终止信号、读、写数据的操作&#xff1b; 2.了解温湿度传感器控制芯片SI7006的工作原理&#…

【C++】飞机大战项目记录

源代码与图片参考自《你好编程》的飞机大战项目&#xff0c;这里不进行展示。 本项目是仅供学习使用的项目 飞机大战项目记录 飞机大战设计报告1 项目框架分析1.1 敌机设计&#xff1a;1.2 玩家飞机控制&#xff1a;1.3 子弹发射&#xff1a;1.4 游戏界面与互动&#xff1a;1.5…

解决Linux根分区空间不足的方法:利用Home分区进行扩容

前言 在进行系统安装时&#xff0c;一个常见的困扰是默认分区设置可能导致home分区拥有过多的空间&#xff0c;而root分区却显得十分紧缺。这种情况下&#xff0c;用户往往会陷入无法继续安装软件或存储文件的困境。本文将向您展示如何通过合理的调整&#xff0c;将home分区中多…

二叉排序树及实现

二叉排序树及实现 二叉排序树&#xff08;Binary Sort Tree, BST&#xff09;又称为二叉查找树。在一般情况下&#xff0c;查询效率要比链表结构要高。对于二叉排序树中的任何一个非叶子节点&#xff0c;要求左子节点的值比当前节点的值小&#xff0c;右子节点的值比当前节点的…

【6】mysql查询性能优化-关联子查询

【README】 0. 先说结论&#xff1a;一般用inner join来改写in和exist&#xff0c;用left join来改写not in&#xff0c;not exist&#xff1b;&#xff08;本文会比较内连接&#xff0c;包含in子句的子查询&#xff0c;exist的性能 &#xff09; 1. 本文总结自高性能mysql 6…

Python 面向对象——1.基本概念

本章学习链接如下&#xff1a; 基本概念与语法 类&#xff08;Class&#xff09;&#xff1a;定义了一组对象共有的属性和方法的蓝图。类是创建对象的模板。 对象&#xff08;Object&#xff09;&#xff1a;类的实例。对象包含实际的数据和操作数据的方法。 属性&#xff0…

NLP_知识图谱_三元组实战

文章目录 三元组含义如何构建知识图谱模型的整体结构基于transformers框架的三元组抽取baselinehow to use预训练模型下载地址训练数据下载地址 结构图代码及数据bertconfig.jsonvocab.txt datadev.jsonschemas.jsontrain.jsonvocab.json 与bert跟data同个目录model.pytrain.py…

原型和原型链--图解

https://juejin.cn/post/7255605810453217335 prototype是函数的属性&#xff08;一个对象&#xff09;&#xff0c;不是对象的属性&#xff0c;普通函数和构造函数的prototype属性是空对象&#xff5b;&#xff5d;&#xff08;其实有2个属性&#xff0c;一个是constructor&a…

Vue3: toRefs与toRef的基本使用

一、前言 本文主要介绍toRefs与toRef的基本使用。 二、内容 1、基本概念 作用: toRefs与toRef可以将一个响应式对象中的每一 个属性&#xff0c;转换为ref对象&#xff1b;不同 toRefs与toRef功能一致&#xff0c;但toRefs可以批量转换。 2、toRefs 如果把reactive定义的…