解锁棋盘之谜:探索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,一经查实,立即删除!

相关文章

前后端跨域请求代码实战(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 代码会进…

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;不可变形式是安全的。 简单…

大厂面试精华面试刷题

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从数组中…

【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分区中多…

【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定义的…

记录交叉编译环境配置--海思开发板的 嵌入式nginx和 php的移植

嵌入式 lnmp搭建的记录 一些交叉编译的配置环境思路分享&#xff1a;P&#xff1a;php编译PHP可能遇到的问题configure阶段&#xff1a;Makefile-make阶段&#xff1a;Makefile-make install阶段&#xff1a; N&#xff1a;Nginx 文章比较水&#xff0c;并没有没解决什么实际问…

二维码门楼牌管理应用平台建设:助力场所整改与消防安全

文章目录 前言一、二维码门楼牌管理应用平台的构建背景二、二维码门楼牌管理应用平台在场所整改中的作用三、二维码门楼牌管理应用平台的意义与价值四、二维码门楼牌管理应用平台的未来展望 前言 随着城市管理的日益精细化&#xff0c;二维码门楼牌管理应用平台的建设成为了提…

C++ - STL详解(七)— stack和queue的介绍及使用

目录 一. stack 1.1 stack的介绍 1.2 stack的定义 1.3 stack的使用 ​编辑 二. queue 2.1 queue的介绍 2.2 queue的定义 2.3 queue的使用 一. stack 1.1 stack的介绍 stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除…

如何通过Postgres的日志进行故障排查?

文章目录 一、配置日志记录二、查看和分析日志三、使用日志进行故障排查的示例四、总结 在进行数据库管理和维护时&#xff0c;日志分析是一项至关重要的技能。PostgreSQL的日志记录功能可以帮助我们追踪数据库的运行状态&#xff0c;定位问题&#xff0c;以及优化性能。下面&a…

【Java】如何获取客户端IP地址

在项目中往往涉及到“获取客户端IP地址”&#xff0c;常见到下面这样子的代码&#xff1a; package com.utils;import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.http.server.reactive.ServerHttpRequest; import java.net…

逻辑运算符

一 介绍 用于连接多个条件&#xff08; 多个关系表达式&#xff09; &#xff0c; 最终的结果也是一个 boolean 值。 &&#xff1a;逻辑与&&&#xff1a;短路与|&#xff1a;逻辑或||&#xff1a;短路或&#xff01; 取反^&#xff1a;异或 二 逻辑运算规则 a&a…

K210基础实验——独立按键中断

前言 学习K210开发板的独立按键和中断功能 一、涉及到的外设资源是K210开发板上的BOOT按键和RGB灯 二、BOOT按键按下&#xff0c;MCU上连接BOOT的IO口变为低电平&#xff0c;松开后为高电平 三、引脚对应关系 BOOT : IO16 RGB灯&#xff1a; R:IO6 G:IO7 B:IO8 四、在…

【linux】多路径|Multipath I/O 技术

目录 简略 详细 什么是多路径? Multipath安装与使用 安装 使用 Linux下multipath软件介绍 附录 配置文件说明 其他解 简略 略 详细 什么是多路径? 普通的电脑主机都是一个硬盘挂接到一个总线上&#xff0c;这里是一对一的关系。 而到了分布式环境&#xff0c;主机和存储网络连…