【Leetcode hot 100】51.N皇后

问题链接

51.N皇后

问题描述

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

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

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

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

示例 1:

输入:n = 4

输出:[[".Q...","...Q","Q...","...Q."],["...Q.","Q...","...Q",".Q..."]]

解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1

输出:[["Q"]]

提示:

  • 1 <= n <= 9

问题解答

解题思路

  1. 核心约束:皇后不能同行、同列、同斜线(45°和135°),因此可通过「按行放置」规避同行问题(每行仅放1个皇后)。
  2. 回溯逻辑
    • 终止条件 :当遍历到第 n 行(行号从0开始)时,说明所有皇后已合法放置,将当前棋盘加入结果集。
    • 递归尝试 :对当前行的每一列,判断该位置是否合法(无同列、同斜线皇后),若合法则放置皇后,递归处理下一行,最后回溯(撤销当前皇后,尝试下一列)。
  3. 合法性校验
    • 检查当前列的上方是否有皇后(同列约束)。
    • 检查当前位置左上斜线(行-1、列-1方向)是否有皇后(45°约束)。
    • 检查当前位置右上斜线(行-1、列+1方向)是否有皇后(135°约束)。

完整 Java 代码

java 复制代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Solution {
    // 存储所有合法的 N 皇后方案
    private List<List<String>> result = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        // 初始化棋盘:n×n 大小,初始值为 '.'(空位)
        char[][] chessboard = new char[n][n];
        for (char[] row : chessboard) {
            Arrays.fill(row, '.');
        }
        // 从第 0 行开始回溯
        backtrack(n, 0, chessboard);
        return result;
    }

    /**
     * 回溯函数:尝试在第 row 行放置皇后
     * @param n 棋盘大小
     * @param row 当前处理的行号(从0开始)
     * @param chessboard 当前棋盘状态
     */
    private void backtrack(int n, int row, char[][] chessboard) {
        // 终止条件:所有行都已放置皇后(row == n)
        if (row == n) {
            // 将 char[][] 棋盘转换为 List<String> 格式,加入结果集
            result.add(convertChessboard(chessboard));
            return;
        }

        // 遍历当前行的每一列,尝试放置皇后
        for (int col = 0; col < n; col++) {
            // 校验当前位置 (row, col) 是否合法
            if (isValid(row, col, chessboard, n)) {
                // 放置皇后
                chessboard[row][col] = 'Q';
                // 递归处理下一行
                backtrack(n, row + 1, chessboard);
                // 回溯:撤销当前位置的皇后,尝试下一列
                chessboard[row][col] = '.';
            }
        }
    }

    /**
     * 校验 (row, col) 位置是否合法(无同列、同斜线皇后)
     * @param row 当前行号
     * @param col 当前列号
     * @param chessboard 棋盘状态
     * @param n 棋盘大小
     * @return 合法返回 true,否则 false
     */
    private boolean isValid(int row, int col, char[][] chessboard, int n) {
        // 1. 检查当前列的上方是否有皇后(同列约束)
        for (int i = 0; i < row; i++) {
            if (chessboard[i][col] == 'Q') {
                return false;
            }
        }

        // 2. 检查左上斜线(行-1,列-1)是否有皇后(45°约束)
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }

        // 3. 检查右上斜线(行-1,列+1)是否有皇后(135°约束)
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }

        return true;
    }

    /**
     * 将 char[][] 格式的棋盘转换为 List<String> 格式
     * @param chessboard 原始棋盘
     * @return 转换后的字符串列表
     */
    private List<String> convertChessboard(char[][] chessboard) {
        List<String> board = new ArrayList<>();
        for (char[] row : chessboard) {
            board.add(new String(row));
        }
        return board;
    }
}

代码解释

  1. 初始化棋盘 :通过 char[][] 存储棋盘(String 不可变,char 数组更易修改),初始所有位置为 .
  2. 回溯函数 backtrack
    • 按行遍历,每行尝试所有列;
    • 合法位置放置皇后后,递归处理下一行;
    • 递归返回后回溯(恢复为 .),确保后续尝试不受影响。
  3. 合法性校验 isValid
    • 仅需检查「上方」的列和斜线(下方未处理,无皇后),减少冗余计算;
    • 斜线遍历通过「行-1、列±1」实现,边界条件(i >=0j >=0j <n)避免数组越界。
  4. 棋盘转换 convertChessboard :将 char[][] 每行转换为 String,符合题目返回格式 List<List<String>>

复杂度分析

  • 时间复杂度O(n! * n)。n! 是所有可能的列选择(每行1列,无同列),每个方案需 O(n²) 校验合法性(实际优化后为 O(n),仅检查上方),整体近似 O(n! * n)
  • 空间复杂度O(n²)。递归栈深度为 n(行号从0到n-1),棋盘存储为 ,结果集存储所有方案(最坏情况 O(n! * n),不计入算法本身空间)。
相关推荐
酉鬼女又兒1 小时前
零基础入门Linux指南:每天一个Linux命令_pwd
linux·运维·服务器
大江东去浪淘尽千古风流人物1 小时前
【VLN】VLN(Vision-and-Language Navigation视觉语言导航)算法本质,范式难点及解决方向(1)
人工智能·python·算法
云飞云共享云桌面1 小时前
高性能图形工作站的资源如何共享给10个SolidWorks研发设计用
linux·运维·服务器·前端·网络·数据库·人工智能
zl_dfq1 小时前
Linux 之 【多线程】(pthread_xxx、轻量级进程、原生线程库、线程ID、__thread、线程栈、线程与信号、线程与程序替换)
linux
choke2331 小时前
Python 基础语法精讲:数据类型、运算符与输入输出
java·linux·服务器
AZ996ZA2 小时前
自学linux的第二十一天【DHCP 服务从入门到实战】
linux·运维·服务器·php
_OP_CHEN2 小时前
【Linux系统编程】(二十八)深入 ELF 文件原理:从目标文件到程序加载的完整揭秘
linux·操作系统·编译·c/c++·目标文件·elf文件
努力学算法的蒟蒻2 小时前
day79(2.7)——leetcode面试经典150
算法·leetcode·职场和发展
2401_841495642 小时前
【LeetCode刷题】二叉树的层序遍历
数据结构·python·算法·leetcode·二叉树··队列
AC赳赳老秦2 小时前
2026国产算力新周期:DeepSeek实战适配英伟达H200,引领大模型训练效率跃升
大数据·前端·人工智能·算法·tidb·memcache·deepseek