解锁棋盘之谜:探索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 found
        if row == n:
            board = build_board(state)
            solutions.append(board)
            return
        
        for col in range(n):
            curr_diagonal = row - col
            curr_anti_diagonal = row + col
            
            # If the queen is not placeable
            if (col in cols or curr_diagonal in diagonals or curr_anti_diagonal in anti_diagonals):
                continue
            
            # "Add" queen to the board
            cols.add(col)
            diagonals.add(curr_diagonal)
            anti_diagonals.add(curr_anti_diagonal)
            state.append(col)
            
            # Move on to the next row with the updated state
            backtrack(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 board

    solutions = []
    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)
            return
        
        available_positions = (~(

cols | diag1 | diag2)) & ((1 << n) - 1)
        
        while available_positions:
            position = available_positions & -available_positions
            col = bin(position).count('0') - 1
            state.append(col)
            backtrack(row + 1, cols | position, (diag1 | position) << 1, (diag2 | position) >> 1, state)
            state.pop()
            available_positions &= available_positions - 1

    def build_board(state):
        board = []
        for i in range(n):
            row = ['.' for _ in range(n)]
            row[state[i]] = 'Q'
            board.append(''.join(row))
        return board

    solutions = []
    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])
            return
        
        for 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] = True
                backtrack(row + 1)
                board[row][col] = '.'
                cols[col] = diag1[row + col] = diag2[row - col + n - 1] = False

    board = [["."]*n for _ in range(n)]
    cols = [False]*n
    diag1 = [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 None
        for 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 results

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软考138-上午题-【软件工程】-软件评审

一、软件评审 通常&#xff0c;把“质量”理解为“用户满意程度”。为了使得用户满意&#xff0c;有以下两个必要条件&#xff1a; (1) 设计的规格说明书符合用户的要求&#xff0c;这称为设计质量。 (2) 程序按照设计规格说明所规定的情况正确执行&#xff0c;这称为程序质…

Docker安装教程,什么系统都有

下载Docker 如果你的系统是图形界面的&#xff0c;比如windows、mac、ubuntu等&#xff0c;到 Docker 官网下载 Docker Desktop。 官网链接: https://www.docker.com/products/docker-desktop/ 根据你的系统选择对应的安装包&#xff0c;然后下载&#xff0c;是不是特别简单&a…

Git TortoiseGit 安装使用详细教程

前言 Git 是一个免费的开源分布式版本控制系统&#xff0c;是用来保存工程源代码历史状态的命令行工具&#xff0c;旨在处理从小型到非常大型的项目&#xff0c;速度快、效率高。《请查阅Git详细说明》。TortoiseGit 是 Git 的 Windows Shell 界面工具&#xff0c;基于 Tortoi…

改进前后端交互实例

前后端交互实例(javaweb05)-CSDN博客 在这之前我假设大家都已经学完了IOC和DI 不明白的这里我也解释一下,首先是两个概念 1.控制反转:对象的创建控制权由程序自身转到外部(容器) 2.依赖注入:容器为程序提供运行时所依赖的资源 Bean对象:IOC容器中创建,关联的对象,称之为be…

【wpf】ObservableCollection 跨线程报错问题

背景 ObservableCollection 我们之前介绍过他和List的区别。ObservableCollection 的好处在于&#xff0c;当集合发生变化时&#xff0c;能发送通知通知界面发生相应的更改。但是ObservableCollection 有个弊端。无法在非UI线程中访问。 要么就是通知失效了&#xff0c;要么就…

从0到1实现RPC | 接入Apollo配置中心

一、代码实现 添加依赖 添加apollo客户端的依赖和spring配置相关依赖 添加监听器 通过实现ApplicationContextAware接口&#xff0c;获取Spring上下文。 使用ApolloConfigChangeListener注解监听命名空间rpc-demo-provider.yaml和默认的application.properties。 监听逻辑…

前端页面助手 (vue)

快速开发页面&#xff08;图形化开发页面&#xff09; 自主编辑 然后自己也可以修改属性 最后导出页面即可 github地址 ;https://github.com/opentiny/tiny-engine

虹科Pico汽车示波器 | 免拆诊断案例 | 2016款保时捷911 GT3 RS车发动机异响

一、故障现象 一辆2016款保时捷911 GT3 RS车&#xff0c;搭载4.0 L水平对置发动机&#xff08;型号为MA176&#xff09;&#xff0c;累计行驶里程约为4.2万km。车主反映&#xff0c;1星期前上过赛道&#xff0c;现在发动机有“哒哒”异响。 二、故障诊断 接车后试车&#xff…

C++语言·类和对象(下)

1. 初始化列表 我们回忆上节写的MyQueue类&#xff0c;其中有两个栈类和一个int类型&#xff0c;栈类因为其特殊性&#xff0c;要开空间&#xff0c;所以我们必须手搓Stack类的构造函数。但是正常来说MyQueue自动生成的构造函数会调用自定义类型的默认构造函数&#xff0c;也就…

Proxy 代理

意图 为其它对象提供一种代理以控制这个对象的访问。 结构 Proxy保存一个引用使得代理可以访问实体&#xff1b;提供一个与Subject的接口相同的接口&#xff0c;使代理可以用来替代实体&#xff1b;控制实体的存取&#xff0c;并可能负责创建和删除它&#xff1b;其他功能依赖…

【leetcode面试经典150题】63. 删除链表的倒数第 N 个结点(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

现货白银保证金交易要先分析趋势

现货白银是保证金交易品种&#xff0c;买卖过程中可能会涉及数十倍的资金杠杆&#xff0c;所以它对投资者的分析水平和交易水平的要求都比较高&#xff0c;所以在进入这个市场之前&#xff0c;投资者需要先学习一些基本的分析方法&#xff0c;当中可以分为基本面和技术面两大流…

Vmware ---快捷键

Vi 文件名.c xrandr 查看分辨率 xrandr -s 分辨率 调你自己想要的分辨率 ctr shift 放大字体 ctr - 缩小字体 ctr alt t 打开控制台 cd caoshupei 进入曹树培文件夹 cd .. 退回上层文件夹 ls 列出生成的文件 ls -a 显示所有文件&#xff0c;包含隐藏的文件和文件…

2024-4-狼道

2024-4-狼道 2024-4-9 宋犀堃&#xff08;堃通坤&#xff0c;多用于人名&#xff09; fatux&#xff1a; 做人当如狗&#xff0c;和蔼可亲&#xff1b;做事当如狼&#xff0c;专注果决。 狼道 智慧生存的强者法则 走向卓越的成功之道 狼道&#xff0c;是追求卓越的野心&am…

第一个Python程序

1、python与java的区别 Python和Java是两种不同的编程语言&#xff0c;它们具有以下一些主要区别&#xff1a; 语法&#xff1a;Python的语法相对简洁和可读性高&#xff0c;使用缩进来表示代码块&#xff1b;而Java的语法更为严格&#xff0c;使用花括号来表示代码块。 类型…

后端-MySQL-week11 事务

事务 简介 操作 有两种方式&#xff0c;一种是设置为手动提交——不执行“commit”不进行变更&#xff1b;另一种是手动开启一个事务&#xff0c;用开启事务的代码&#xff08;SQL语句&#xff09;来创建一个需要“commit”才能进行变更的事务 1.第一种方式 2.第二种方式 四…

会声会影2023序列号免费和激活下载(附注册机keygen下载)

安装前准备 1、会声会影2023的安装需要在保证电脑联网的状态下进行。请您确保安装过程中有良好的网络环境&#xff0c;并且在安装过程中不可断网。 2、安装之前&#xff0c;请先退出、关闭360、电脑管家以及杀毒软件。 会声会影2023安装和下载 1、选择您下载版本对应的会声会…

配置使用IPsec安全框架保护RIPng报文

正文共&#xff1a;999 字 11 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面我们简单介绍了IPv6的基本概念&#xff08;IPv6从入门到精通&#xff09;&#xff0c;也做了动态路由协议的相关介绍&#xff08;IS-ISv6配置&#xff09;&#xff0c;还做了一个综合性比较强的…

抓取内网windows密码和利用hash横向及相关问题

目录 实验准备 用msf拿到shell 抓取hash和明文密码 相关问题 问题1.通过hashdump抓取所有用户的密文为什么分成两个模块&#xff0c;这两个模块分别代表什么 &#xff1f; 问题2.为什么第一个模块 永远是一样的aad3&#xff1f; 问题3.这两个模块的加密算法有什么不同&a…

Android Jetpack学习系列——Room

关于Room&#xff1a; Room是Android Jetpack组件之一&#xff0c;旨在为Android应用程序提供一种简单、强大且易于使用的本地数据库访问解决方案。 关键特性&#xff1a; 1.基于SQLite封装&#xff1a;Room是基于SQLite数据库引擎构建的&#xff0c;提供了面向对象的API来与…