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

news2024/11/17 1:28:18

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

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

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

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

相关文章

【Qt 学习笔记】Qt常用控件 | 显示类控件Label的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 显示类控件Label的使用及说明 文章编号&#xff1a;Qt 学…

AOP基础-动态代理

文章目录 1.动态代理1.需求分析2.动态代理的核心3.代码实例1.Vehicle.java2.Car.java3.Ship.java4.VehicleProxyProvider.java(动态代理模板)5.测试使用 2.动态代理深入—横切关注点1.需求分析2.四个横切关注点3.代码实例1.Cal.java2.CalImpl.java3.VehicleProxyProvider02.jav…

iOS重签名-超详细,附排错

文章目录 重签名步骤步骤 1: 准备必要的材料步骤 2: 解压 .ipa 文件步骤3:将 Provisioning Profile 复制到 Payload 目录步骤 4: 移除原来的签名步骤 5: 使用新的证书和 Provisioning Profile 进行重签名步骤 6: 重新打包 .ipa 文件步骤 7: 安装和测试得到provisioning file和…

语音转换中的扩散模型——DDDM-VC

DDDM-VC: Decoupled Denoising Diffusion Models with Disentangled Representation and Prior Mixup for Verifed Robust Voice Conversion https://ojs.aaai.org/index.php/AAAI/article/view/29740https://ojs.aaai.org/index.php/AAAI/article/view/29740 1.概述 首先,语…

力扣HOT100 - 142. 环形链表 II

解题思路&#xff1a; public class Solution {public ListNode detectCycle(ListNode head) {Set<ListNode> set new HashSet<>();while (head ! null) {if (!set.add(head)) {return head;}head head.next;}return null;} }

findImg找图工具

findImg 安装 npm install findImg -g 启动 findImg run 介绍 找出当前目录下的所有图片&#xff08;包括svg的symbol格式&#xff09;在浏览器中显示出来 源码 https://github.com/HuXin957/find-img 场景 例如前端项目中的img目录&#xff0c;大家都在往里面放图片&#xff…

k8s 控制器StatefulSet原理解析

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、k8s概述 2、有状态服务和无状态服务…

(自学用)正演理论

基于波动方程如何解决数值频散问题——快速正演方法 NAD方法&#xff1a; 怎样离散/逼近高阶偏导数&#xff08;如何采样&#xff09;&#xff1a; 传统方法是用某一点及其周围点的函数f的线性组合来逼近导数。只有函数值&#xff0c;要想提高精度&#xff0c;压制数值频散就必…

与助听器相关的职业主要有哪些?

助听装置是目前解决听觉障碍的几乎唯一科学的方法。然而助听装置改变的不是听力&#xff0c;而是外界的声音信息。也就是助听装置只能将外界的声音信息改变成能够适应听觉障碍患者听觉动态范围的声音。显然助听器并不知道听觉障碍患者的听觉动态范围是多少&#xff1f;也不知道…

PyTorch and Stable Diffusion on FreeBSD

Stable Diffusion在图像生成领域具有广泛的应用和显著的优势。它利用深度学习和扩散模型的原理&#xff0c;能够从随机噪声中生成高质量的图像。 官网&#xff1a;GitHub - verm/freebsd-stable-diffusion: Stable Diffusion on FreeBSD with CUDA support FreeBSD下难度主要…

数据输入输出流(I/O)

文章目录 前言一、数据输入输出流是什么&#xff1f;二、使用方法 1.DataInputStream类2.DataOutoutStream类3.实操展示总结 前言 数据输入输出流也是将文件输入输出流打包后使用的对象。相比于文件输入输出流&#xff0c;数据输入输出流提供了简单易用的方法去操作不同类型的数…

【系统架构师】-案例考点(一)

1、软件架构设计 主要考点&#xff1a; 质量属性、软件架构风格、软件架构评估、MVC架构、面向服务的SOA架构、 DSSA、ABSD 1.1、质量属性 1、性能:指系统的响应能力&#xff0c;即要经过多长时间才能对某个事件做出响应&#xff0c;或者在某段时间内系统所能处理的事件的…

不同版本vue安装vue-router

vue-router 是vue官网发布的一个插件库&#xff0c;单页面路由。vue 和 vue-router 之间版本也需要对应。 vue2.x版本使用vue-router3.x版本&#xff0c;vue3.x使用vue-router4.x版本&#xff0c;根据自己的需要选择合适的版本 1、可以在安装前查看vue-router版本&#xff0c;…

K8S哲学 - probe 探针

探针分类&#xff1a; liveness probe readiness probe startup probe Liveness Probe&#xff1a;用于检查容器是否还在运行。如果 Liveness Probe 失败&#xff0c;Kubernetes 会杀死容器&#xff0c;然后根据你的重启策略来决定是否重新启动容器。常见的做法是使用与 Readin…

深度学习:Pytorch分布式训练

深度学习&#xff1a;Pytorch分布式训练 简介模型并行数据并行参考文献 简介 在深度学习领域&#xff0c;模型越来越庞大、数据量不断增加&#xff0c;训练这些大型模型越来越耗时。通过在多个GPU或多个节点上并行地训练模型&#xff0c;我们可以显著减少训练时间。此外&#…

Python长时间序列遥感数据处理及在全球变化、物候提取、植被变绿与固碳分析、生物量估算与趋势分析等领域中的应用

植被是陆地生态系统中最重要的组分之一&#xff0c;也是对气候变化最敏感的组分&#xff0c;其在全球变化过程中起着重要作用&#xff0c;能够指示自然环境中的大气、水、土壤等成分的变化&#xff0c;其年际和季节性变化可以作为地球气候变化的重要指标。此外&#xff0c;由于…

安装Hexo上传插件时,使用hexo d 报错“Spawn Failed”

问题如下&#xff1a; 解决方案&#xff1a; 找到deploy的配置文件 将配置文件增加 [user]email xxxx你git的邮箱地址name 你git的用户名 然后执行hexo clean清除一下后&#xff0c;执行hexo d&#xff0c;会弹出让你登录git的账号和密码&#xff0c;登录后就上传成功了。 …

Java 判断两个Date类型的时间是否大于6天

判断两个Date类型的时间是否大于6天 new Date().toInstant() 是获取当前时间&#xff0c;并转换成Instant对象 cardDeviceTrajectoryInfo.getGpstime().toInstant() 是表中最后一条数据的时间&#xff0c;并转换成Instant对象 // 计算两个时间的间隔 long daysBetween ChronoU…

【基础IO】谈谈动静态库(怒肝7000字)

文章目录 前言实验代码样例静态库生成一个静态库归档工具ar静态库的链接 动态库创建动态库加载动态库 动静态链接静态链接动态链接动静态链接的优缺点 前言 在软件开发中&#xff0c;库&#xff08;Library&#xff09;是一种方式&#xff0c;可以将代码打包成可重用的格式&…

隧道代理的优势与劣势分析

“随着互联网的快速发展&#xff0c;网络安全已经成为一个重要的议题。为了保护个人和组织的数据&#xff0c;隧道代理技术逐渐成为网络安全的重要工具。隧道代理通过在客户端和服务器之间建立安全通道&#xff0c;加密和保护数据的传输&#xff0c;有效地防止黑客入侵和信息泄…