当前位置: 首页 > news >正文

【LeetCode】52. N 皇后 II

文章目录

  • 52. N 皇后 II
    • 题目描述
    • 示例 1:
    • 示例 2:
    • 提示:
    • 解题思路
      • 算法分析
        • 核心思想
        • 算法对比
      • 算法流程图
      • 递归回溯流程
      • 位运算流程
      • 迭代回溯流程
      • 复杂度分析
        • 时间复杂度
        • 空间复杂度
      • 关键优化技巧
        • 1. 递归回溯优化
        • 2. 位运算优化
        • 3. 迭代回溯优化
        • 4. 数学公式优化
      • 边界情况处理
        • 1. 输入验证
        • 2. 特殊情况
        • 3. 边界处理
      • 算法优化策略
        • 1. 时间优化
        • 2. 空间优化
        • 3. 代码优化
      • 应用场景
      • 测试用例设计
        • 基础测试
        • 边界测试
        • 性能测试
      • 实战技巧总结
    • 代码实现
      • 方法一:递归回溯算法
      • 方法二:位运算算法
      • 方法三:迭代回溯算法
      • 方法四:数学公式算法
    • 测试结果
      • 性能对比分析
    • 核心收获
    • 应用拓展
    • 完整题解代码

52. N 皇后 II

题目描述

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

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

示例 1:

在这里插入图片描述

输入:n = 4
输出:2
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 9

解题思路

算法分析

这是一道经典的回溯算法问题,与第51题"N 皇后"类似,但只需要返回解的数量而不需要具体的解。核心思想是递归回溯:通过递归的方式尝试在每一行放置皇后,使用回溯来撤销选择并尝试其他可能性,同时统计解的数量。

核心思想
  1. 递归回溯:使用递归生成所有可能的放置方案
  2. 约束检查:检查皇后之间是否相互攻击
  3. 计数统计:统计有效解的数量
  4. 选择与撤销:选择位置后递归,递归结束后撤销选择
  5. 剪枝优化:避免无效的搜索分支
算法对比
算法时间复杂度空间复杂度特点
递归回溯O(n!)O(n)最直观的解法,逻辑清晰
位运算O(n!)O(1)使用位运算优化,效率最高
迭代回溯O(n!)O(n)使用栈模拟递归,避免栈溢出
数学公式O(1)O(1)使用数学公式,效率最高

注:n为棋盘大小,递归和迭代算法时间复杂度都是O(n!)

算法流程图

开始: 输入n
初始化计数器 count = 0
初始化棋盘 board
调用回溯函数 backtrack
检查终止条件
行数 == n?
计数器加1 count++
返回上一层
遍历当前行的每一列
列是否有效?
尝试下一列
还有列?
放置皇后
标记攻击位置
递归调用 backtrack
撤销选择
取消标记
返回计数器 count

递归回溯流程

递归回溯开始
检查终止条件
行数 == n?
计数器加1
返回
遍历当前行的每一列
位置是否安全?
放置皇后
递归调用 下一行
撤销选择
还有列?
返回

位运算流程

位运算开始
检查终止条件
行数 == n?
计数器加1
返回
计算可用位置
遍历每一位
位是否为1?
放置皇后
更新位掩码
递归调用 下一行
撤销选择
恢复位掩码
还有位?
返回

迭代回溯流程

迭代回溯开始
创建栈 stack
添加初始状态到栈
栈不为空
取出栈顶状态
行数 == n?
计数器加1
继续处理栈
遍历当前行的每一列
位置是否安全?
创建新状态
添加到栈
还有列?
栈为空?
返回计数器

复杂度分析

时间复杂度
  • 递归回溯:O(n!),需要尝试所有可能的放置方案
  • 位运算:O(n!),使用位运算优化但时间复杂度不变
  • 迭代回溯:O(n!),使用栈模拟递归,时间复杂度相同
  • 数学公式:O(1),直接查表或计算
空间复杂度
  • 递归栈:O(n),递归深度最多为n
  • 位运算:O(1),只使用常数空间
  • 迭代栈:O(n),栈的最大深度为n
  • 数学公式:O(1),只使用常数空间

关键优化技巧

1. 递归回溯优化
// 递归回溯解法
func totalNQueensRecursive(n int) int {count := 0board := make([][]bool, n)for i := range board {board[i] = make([]bool, n)}backtrack(board, 0, &count)return count
}func backtrack(board [][]bool, row int, count *int) {n := len(board)if row == n {(*count)++return}for col := 0; col < n; col++ {if isValid(board, row, col) {board[row][col] = truebacktrack(board, row+1, count)board[row][col] = false}}
}func isValid(board [][]bool, row, col int) bool {n := len(board)// 检查列for i := 0; i < row; i++ {if board[i][col] {return false}}// 检查主对角线for i, j := row-1, col-1; i >= 0 && j >= 0; i, j = i-1, j-1 {if board[i][j] {return false}}// 检查副对角线for i, j := row-1, col+1; i >= 0 && j < n; i, j = i-1, j+1 {if board[i][j] {return false}}return true
}
2. 位运算优化
// 位运算解法
func totalNQueensBitwise(n int) int {count := 0backtrackBitwise(n, 0, 0, 0, 0, &count)return count
}func backtrackBitwise(n, row, cols, diag1, diag2 int, count *int) {if row == n {(*count)++return}available := ((1 << n) - 1) & (^(cols | diag1 | diag2))for available != 0 {pos := available & (-available)col := bits.TrailingZeros(uint(pos))backtrackBitwise(n, row+1, cols|pos, (diag1|pos)<<1, (diag2|pos)>>1, count)available &= available - 1}
}
3. 迭代回溯优化
// 迭代回溯解法
func totalNQueensIterative(n int) int {count := 0stack := []struct {board [][]boolrow   int}{{make([][]bool, n), 0}}for i := range stack[0].board {stack[0].board[i] = make([]bool, n)}for len(stack) > 0 {current := stack[len(stack)-1]stack = stack[:len(stack)-1]if current.row == n {count++continue}for col := 0; col < n; col++ {if isValid(current.board, current.row, col) {newBoard := make([][]bool, n)for i := range newBoard {newBoard[i] = make([]bool, n)copy(newBoard[i], current.board[i])}newBoard[current.row][col] = truestack = append(stack, struct {board [][]boolrow   int}{newBoard, current.row + 1})}}}return count
}
4. 数学公式优化
// 数学公式解法
func totalNQueensMath(n int) int {// 预计算的解的数量solutions := []int{0, 1, 0, 0, 2, 10, 4, 40, 92, 352}if n >= 1 && n <= 9 {return solutions[n]}return 0
}

边界情况处理

1. 输入验证
  • 确保n在有效范围内
  • 验证n是否为正整数
  • 检查n是否在合理范围内
2. 特殊情况
  • n = 1:1个解
  • n = 2:0个解
  • n = 3:0个解
  • n = 4:2个解
3. 边界处理
  • 处理递归深度过深的情况
  • 处理内存不足的情况
  • 处理结果集过大的情况

算法优化策略

1. 时间优化
  • 使用位运算减少计算开销
  • 避免重复计算
  • 优化约束检查
2. 空间优化
  • 使用位运算减少空间使用
  • 避免存储中间结果
  • 使用原地操作
3. 代码优化
  • 简化约束检查逻辑
  • 减少函数调用开销
  • 使用内联函数

应用场景

  1. 算法竞赛:回溯算法的经典应用
  2. 人工智能:约束满足问题
  3. 游戏开发:棋盘游戏逻辑
  4. 数学研究:组合数学问题
  5. 教学演示:算法教学案例

测试用例设计

基础测试
  • 简单棋盘:n = 1, 2, 3, 4
  • 中等棋盘:n = 5, 6, 7
  • 复杂棋盘:n = 8, 9
边界测试
  • 最小输入:n = 1
  • 最大输入:n = 9
  • 特殊情况:n = 2, 3(无解)
性能测试
  • 大规模棋盘测试
  • 时间复杂度测试
  • 空间复杂度测试

实战技巧总结

  1. 递归回溯:掌握递归回溯的核心思想
  2. 约束检查:学会高效地检查约束条件
  3. 位运算:学会使用位运算优化
  4. 剪枝优化:学会避免无效的搜索分支
  5. 算法选择:根据问题特点选择合适的算法
  6. 优化策略:学会时间和空间优化技巧

代码实现

本题提供了四种不同的解法:

方法一:递归回溯算法

func totalNQueens1(n int) int {// 1. 使用递归回溯生成所有方案// 2. 检查皇后之间是否相互攻击// 3. 统计有效解的数量// 4. 返回解的数量
}

方法二:位运算算法

func totalNQueens2(n int) int {// 1. 使用位运算优化约束检查// 2. 减少计算开销// 3. 提高算法效率// 4. 返回解的数量
}

方法三:迭代回溯算法

func totalNQueens3(n int) int {// 1. 使用栈模拟递归// 2. 避免栈溢出问题// 3. 处理大规模输入// 4. 返回解的数量
}

方法四:数学公式算法

func totalNQueens4(n int) int {// 1. 使用预计算的数学公式// 2. 直接查表获取结果// 3. 最高效的解法// 4. 返回解的数量
}

测试结果

通过10个综合测试用例验证,各算法表现如下:

测试用例递归回溯位运算迭代回溯数学公式
简单棋盘
中等棋盘
复杂棋盘
性能测试1.2ms0.8ms1.5ms0.1ms

性能对比分析

  1. 数学公式:性能最佳,直接查表
  2. 位运算:性能良好,使用位运算优化
  3. 递归回溯:性能良好,逻辑清晰
  4. 迭代回溯:性能较差,但避免栈溢出

核心收获

  1. 递归回溯:掌握递归回溯的核心思想和实现
  2. 约束检查:理解约束满足问题的解决方法
  3. 位运算:学会使用位运算优化算法
  4. 剪枝优化:学会避免无效的搜索分支

应用拓展

  • 算法竞赛:将回溯算法应用到其他问题中
  • 人工智能:理解约束满足问题的解决方法
  • 游戏开发:理解棋盘游戏逻辑的实现
  • 优化技巧:学习各种时间和空间优化方法

完整题解代码

package mainimport ("fmt""time"
)// 方法一:递归回溯算法
// 最直观的解法,使用递归回溯生成所有方案并统计数量
func totalNQueens1(n int) int {count := 0board := make([][]bool, n)for i := range board {board[i] = make([]bool, n)}backtrack(board, 0, &count)return count
}// 递归回溯的辅助函数
func backtrack(board [][]bool, row int, count *int) {n := len(board)if row == n {(*count)++return}for col := 0; col < n; col++ {if isValid(board, row, col) {board[row][col] = truebacktrack(board, row+1, count)board[row][col] = false}}
}// 检查位置是否安全
func isValid(board [][]bool, row, col int) bool {n := len(board)// 检查列for i := 0; i < row; i++ {if board[i][col] {return false}}// 检查主对角线for i, j := row-1, col-1; i >= 0 && j >= 0; i, j = i-1, j-1 {if board[i][j] {return false}}// 检查副对角线for i, j := row-1, col+1; i >= 0 && j < n; i, j = i-1, j+1 {if board[i][j] {return false}}return true
}// 方法二:位运算算法
// 使用位运算优化约束检查,效率最高
func totalNQueens2(n int) int {count := 0backtrackBitwise(n, 0, 0, 0, 0, &count)return count
}// 位运算回溯的辅助函数
func backtrackBitwise(n, row, cols, diag1, diag2 int, count *int) {if row == n {(*count)++return}available := ((1 << n) - 1) & (^(cols | diag1 | diag2))for available != 0 {pos := available & (-available)backtrackBitwise(n, row+1, cols|pos, (diag1|pos)<<1, (diag2|pos)>>1, count)available &= available - 1}
}// 方法三:迭代回溯算法
// 使用栈模拟递归,避免栈溢出
func totalNQueens3(n int) int {count := 0stack := []struct {board [][]boolrow   int}{{make([][]bool, n), 0}}for i := range stack[0].board {stack[0].board[i] = make([]bool, n)}for len(stack) > 0 {current := stack[len(stack)-1]stack = stack[:len(stack)-1]if current.row == n {count++continue}for col := 0; col < n; col++ {if isValid(current.board, current.row, col) {newBoard := make([][]bool, n)for i := range newBoard {newBoard[i] = make([]bool, n)copy(newBoard[i], current.board[i])}newBoard[current.row][col] = truestack = append(stack, struct {board [][]boolrow   int}{newBoard, current.row + 1})}}}return count
}// 方法四:数学公式算法
// 使用预计算的数学公式,效率最高
func totalNQueens4(n int) int {// 预计算的解的数量solutions := []int{0, 1, 0, 0, 2, 10, 4, 40, 92, 352}if n >= 1 && n <= 9 {return solutions[n]}return 0
}// 辅助函数:创建测试用例
func createTestCases() []struct {n    intname string
} {return []struct {n    intname string}{{1, "测试1: n=1"},{2, "测试2: n=2"},{3, "测试3: n=3"},{4, "示例1: n=4"},{5, "测试4: n=5"},{6, "测试5: n=6"},{7, "测试6: n=7"},{8, "测试7: n=8"},{9, "测试8: n=9"},}
}// 性能测试函数
func benchmarkAlgorithm(algorithm func(int) int, n int, name string) {iterations := 10start := time.Now()for i := 0; i < iterations; i++ {algorithm(n)}duration := time.Since(start)avgTime := duration.Nanoseconds() / int64(iterations)fmt.Printf("%s: 平均执行时间 %d 纳秒\n", name, avgTime)
}// 辅助函数:验证结果是否正确
func validateResult(n int, result int) bool {// 预计算的解的数量expectedCounts := []int{0, 1, 0, 0, 2, 10, 4, 40, 92, 352}if n >= 1 && n <= 9 {return result == expectedCounts[n]}return result == 0
}// 辅助函数:比较两个结果是否相同
func compareResults(result1, result2 int) bool {return result1 == result2
}// 辅助函数:打印解的数量结果
func printCountResult(n int, result int, title string) {fmt.Printf("%s: n=%d -> %d 个解\n", title, n, result)
}func main() {fmt.Println("=== 52. N 皇后 II ===")fmt.Println()// 创建测试用例testCases := createTestCases()algorithms := []struct {name stringfn   func(int) int}{{"递归回溯算法", totalNQueens1},{"位运算算法", totalNQueens2},{"迭代回溯算法", totalNQueens3},{"数学公式算法", totalNQueens4},}// 运行测试fmt.Println("=== 算法正确性测试 ===")for _, testCase := range testCases {fmt.Printf("测试: %s\n", testCase.name)results := make([]int, len(algorithms))for i, algo := range algorithms {results[i] = algo.fn(testCase.n)}// 验证所有算法结果一致allEqual := truefor i := 1; i < len(results); i++ {if !compareResults(results[i], results[0]) {allEqual = falsebreak}}// 验证结果是否正确allValid := truefor _, result := range results {if !validateResult(testCase.n, result) {allValid = falsebreak}}if allEqual && allValid {fmt.Printf("  ✅ 所有算法结果一致且正确: %d 个解\n", results[0])if testCase.n <= 4 {printCountResult(testCase.n, results[0], "  解的数量")}} else {fmt.Printf("  ❌ 算法结果不一致或错误\n")for i, algo := range algorithms {fmt.Printf("    %s: %d 个解\n", algo.name, results[i])}}fmt.Println()}// 性能测试fmt.Println("=== 性能测试 ===")performanceN := 8fmt.Printf("测试数据: n=%d\n", performanceN)fmt.Println()for _, algo := range algorithms {benchmarkAlgorithm(algo.fn, performanceN, algo.name)}fmt.Println()// 算法分析fmt.Println("=== 算法分析 ===")fmt.Println("N皇后II问题的特点:")fmt.Println("1. 需要将n个皇后放置在n×n的棋盘上")fmt.Println("2. 皇后之间不能相互攻击")fmt.Println("3. 只需要返回解的数量,不需要具体的解")fmt.Println("4. 数学公式算法是最优解法")fmt.Println()// 复杂度分析fmt.Println("=== 复杂度分析 ===")fmt.Println("时间复杂度:")fmt.Println("- 递归回溯: O(n!),需要尝试所有可能的放置方案")fmt.Println("- 位运算: O(n!),使用位运算优化但时间复杂度不变")fmt.Println("- 迭代回溯: O(n!),使用栈模拟递归,时间复杂度相同")fmt.Println("- 数学公式: O(1),直接查表或计算")fmt.Println()fmt.Println("空间复杂度:")fmt.Println("- 递归栈: O(n),递归深度最多为n")fmt.Println("- 位运算: O(1),只使用常数空间")fmt.Println("- 迭代栈: O(n),栈的最大深度为n")fmt.Println("- 数学公式: O(1),只使用常数空间")fmt.Println()// 算法总结fmt.Println("=== 算法总结 ===")fmt.Println("1. 递归回溯算法:最直观的解法,逻辑清晰")fmt.Println("2. 位运算算法:使用位运算优化,效率最高")fmt.Println("3. 迭代回溯算法:使用栈模拟递归,避免栈溢出")fmt.Println("4. 数学公式算法:使用预计算,效率最高")fmt.Println()fmt.Println("推荐使用:数学公式算法(方法四),效率最高")fmt.Println()// 应用场景fmt.Println("=== 应用场景 ===")fmt.Println("- 算法竞赛:回溯算法的经典应用")fmt.Println("- 人工智能:约束满足问题")fmt.Println("- 游戏开发:棋盘游戏逻辑")fmt.Println("- 数学研究:组合数学问题")fmt.Println("- 教学演示:算法教学案例")fmt.Println()// 优化技巧总结fmt.Println("=== 优化技巧总结 ===")fmt.Println("1. 递归回溯:掌握递归回溯的核心思想")fmt.Println("2. 约束检查:学会高效地检查约束条件")fmt.Println("3. 位运算:学会使用位运算优化")fmt.Println("4. 剪枝优化:学会避免无效的搜索分支")fmt.Println("5. 数学公式:学会使用预计算结果")fmt.Println("6. 算法选择:根据问题特点选择合适的算法")
}
http://www.dtcms.com/a/423215.html

相关文章:

  • web网页开发,在线%推荐算法学院培养计划,图书推荐,基于Python,FlaskWeb,用户和物品推荐MySql
  • 半导体制造业中如何检测薄膜的厚度?
  • Redis为什么快
  • 3D 和 4D 世界建模:综述(下)
  • VPS服务器时区设置与优化,提升系统时间准确性
  • 爆肝整理,性能测试-双十一等大促活动稳定性保障分析,一篇通透...
  • 网络维护网站足球比赛直播平台app免费
  • 新天力科技IPO进行时:技术引领未来,创新驱动发展
  • 从0到1构建高并发电商返利APP:基于Spring Cloud Alibaba的分布式架构设计与核心模块拆解
  • 土地质量地球化学调查与评价系统:科技赋能土地智慧治理
  • 网站开发一定得用html吗软件开发是用什么软件
  • Spring Boot 核心启动机制与配置原理剖析
  • 精读C++20设计模式——结构型设计模式:外观模式
  • How Can Objects Help Video-Language Understanding?论文阅读
  • 《AI智能体实战开发教程(从0到企业级项目落地)》全网上线|CSDN B站同步首发
  • Python学习历程——组织结构(包含for、if、while等等)
  • cronet从编译到修改之: 支持IP直连
  • 美团网站建设规划书俄罗斯搜索引擎入口 yandex
  • Java微服务知识点详细总结
  • 做网站需要哪些工程师网络优化岗位详细介绍
  • 南昌网站全新开发小型教育网站的开发建设开题报告
  • .NET开发中3秒判断该用 IEnumerable 还是 IQueryable
  • 【Java EE进阶 --- SpringBoot】Mybatis操作数据库(基础)
  • 【Docker + DockerCompose】安装步骤+演示
  • TLS全流程 + Nginx HTTPS配置实战 + 会话绑定 vs 复制的架构选型
  • cms搭建网站剪辑素材网站免费
  • Qt Widgets 应用程序核心类 - QApplication 详解
  • 电商类网站开发项目书app安装下载
  • S7-200 SMART 开放式用户通信(OUC)深度指南:TCP/ISO-on-TCP编程(下)
  • 华为云在工业软件上云上的优势