LeetCode 第51题:N 皇后

120 阅读3分钟

LeetCode 第51题:N 皇后

题目描述

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

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

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

难度

困难

题目链接

点击在LeetCode中查看题目

示例

示例 1:

示例1 输入:n = 4 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] 解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

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

提示

  • 1 <= n <= 9
  • 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一行、同一列或同一斜线上。

解题思路

回溯算法 + 剪枝

这是一道经典的回溯算法题目。关键是要理解皇后的攻击范围,并使用合适的数据结构来判断位置是否可用。

关键点:

  1. 使用回溯法逐行放置皇后
  2. 使用三个集合记录已经被攻击的列、正对角线和反对角线
  3. 利用数学关系快速判断对角线
  4. 需要将结果转换为题目要求的棋盘表示

具体步骤:

  1. 初始化记录攻击位置的集合
  2. 从第一行开始,尝试在每一列放置皇后
  3. 检查当前位置是否可用
  4. 放置皇后并更新攻击范围
  5. 递归处理下一行
  6. 回溯时恢复状态

图解思路

算法步骤分析表

步骤当前行已放置皇后操作说明
初始0[]开始空棋盘
第1步0[1]放置第1个第一行第二列
第2步1[1,3]放置第2个第二行第四列
第3步2[1,3,0]放置第3个第三行第一列
完成3[1,3,0,2]得到解完整方案

状态/情况分析表

情况输入输出说明
n=11[["Q"]]最简单情况
n=442个解决方案标准情况
n=8892个解决方案复杂情况

代码实现

C# 实现

public class Solution {
    private IList<IList<string>> result = new List<IList<string>>();
    private HashSet<int> cols = new HashSet<int>();
    private HashSet<int> diag1 = new HashSet<int>();
    private HashSet<int> diag2 = new HashSet<int>();
    
    public IList<IList<string>> SolveNQueens(int n) {
        int[] queens = new int[n];
        Backtrack(queens, 0, n);
        return result;
    }
    
    private void Backtrack(int[] queens, int row, int n) {
        if (row == n) {
            result.Add(GenerateBoard(queens, n));
            return;
        }
        
        for (int col = 0; col < n; col++) {
            // 检查当前位置是否可用
            if (cols.Contains(col) || 
                diag1.Contains(row + col) || 
                diag2.Contains(row - col)) {
                continue;
            }
            
            // 放置皇后
            queens[row] = col;
            cols.Add(col);
            diag1.Add(row + col);
            diag2.Add(row - col);
            
            // 递归下一行
            Backtrack(queens, row + 1, n);
            
            // 回溯,移除皇后
            cols.Remove(col);
            diag1.Remove(row + col);
            diag2.Remove(row - col);
        }
    }
    
    private IList<string> GenerateBoard(int[] queens, int n) {
        var board = new List<string>();
        for (int i = 0; i < n; i++) {
            char[] row = new char[n];
            Array.Fill(row, '.');
            row[queens[i]] = 'Q';
            board.Add(new string(row));
        }
        return board;
    }
}

执行结果

  • 执行用时:168 ms
  • 内存消耗:42.8 MB

代码亮点

  1. 🎯 使用HashSet快速判断位置可用性
  2. 💡 巧妙利用数学关系处理对角线
  3. 🔍 优化回溯过程,及时剪枝
  4. 🎨 代码结构清晰,模块化设计

常见错误分析

  1. 🚫 对角线判断条件错误
  2. 🚫 回溯时状态恢复不完整
  3. 🚫 棋盘生成格式错误
  4. 🚫 集合使用不当导致状态混乱

解法对比

解法时间复杂度空间复杂度优点缺点
暴力枚举O(n!×n)O(n)思路简单效率极低
回溯+剪枝O(n!)O(n)较好效率实现复杂
位运算优化O(n!)O(n)性能最佳难以理解

相关题目