hot100 N 皇后(51)
本题采用深度优先搜索DFS回溯减枝算法解决 N 皇后棋盘安全布局求解问题。其核心本质是将二维棋盘的皇后攻击判定降维映射为一维空间列、主对角线、副对角线的布尔占位核验通过逐行试探与现场回溯在搜索早期实现物理剪枝。当前提供的源码实现了在最坏时间复杂度 O(n!) 和空间复杂度 O(n) 条件下的全局解空间检索最终走向是精准输出所有不发生任何维度相互攻击的合法棋盘排布方案。一、 问题本质与数据模型对于大小为 n x n 的棋盘n 皇后问题要求放置 n 个棋子并满足任何两个棋子不能处于同一行、同一列或同一斜线上。由于每行必须且只能放置一个皇后算法将搜索维度设定为“逐行推进”。此时行的冲突在算法设计上被天然规避核心防线转移到列与双对角线冲突的判定。如果在每次尝试落子时都对棋盘进行全量八向扫描检测会产生大量的冗余计算。为了在常数时间 O(1) 内完成冲突判定算法引入了“一维布尔占位哈希模型”列冲突判定由于列下标为 c直接使用大小为 n 的布尔数组col进行标记其中col[c]代表第 c 列已被占用。主对角线右上到左下冲突判定在同一条主对角线上所有单元格的行索引与列索引之和r c为固定常数。其取值范围在 [0, 2 * n - 2] 区间内因此使用大小为 2 * n - 1 的布尔数组diag1标记该对角线。副对角线左上到右下冲突判定在同一条副对角线上所有单元格的行索引与列索引之差r - c为固定常数。为了消除可能出现的负数下标需要加上偏移行程n - 1。变换后的索引r - c n - 1取值范围同样在 [0, 2 * n - 2] 区间内因此使用大小为 2 * n - 1 的布尔数组diag2标记该对角线。通过这三个一维布尔数组算法实现了在 2D 棋盘空间内的降维精确投影核验完全消除了冲突检测的遍历开销。二、 算法演进对比在解决 N 皇后全局路径搜索问题时基于 Hashing 的回溯法在时空收敛效率上达到了极致解法名称时间复杂度空间复杂度核心原理物理瓶颈 / 缺陷全棋盘暴力排列组合O(n 的平方 阶乘)O(n 的平方)对所有网格进行全排列随后全扫描检测冲突产生大量无效的分支组合未能在搜索早期物理截断无效节点回溯结合常规扫描检测O(n 阶乘)O(n)逐行放置皇后每次放置前沿对角线和列方向向上扫描冲突每次冲突检测都需要执行 O(r) 的线性扫描操作增加了内层循环的时间常数哈希剪枝回溯法当前解法O(n 阶乘)O(n)利用对角线及列的一维布尔数组实现 O(1) 级的冲突判定与即时回溯依旧面临指数级解空间的物理天花板在 n 较大时如 n 15搜索时间会发生暴涨三、 核心分支控制逻辑与决策证明当前源码的控制流完全依赖于行索引越界基准、三方向状态联合拦截以及现场的标记复原其内部决策分支证明如下1. 基准准入分支if (r col.length)执行构建棋盘字符串列表path并存入ans。物理意义说明行指针已安全移动到棋盘外第 n 行代表当前试探分支下所有 n 个皇后都已安全落子成功捕捉到一个合法的全局解。2. 状态映射与防溢出索引int rc r - c col.length - 1;执行计算副对角线索引。数学证明在副对角线上满足r - c k常数 k。由于列下标 c 可能大于行下标 r导致r - c范围在 [-(n-1), n-1] 内。通过整体平移n - 1即代码中的col.length - 1将其物理偏移行程映射到 [0, 2 * n - 2] 的正整数闭区间消除了数组下标越界ArrayIndexOutOfBoundsException的物理风险。3. 冲突拦截与剪枝分支if (!col[c] !diag1[r c] !diag2[rc])执行仅在列 c、主对角线r c、副对角线rc均为 false 时执行落子。数学证明只有当该位置投影到列、双对角线的三个物理方向均未检测到已有皇后占位时当前落子才满足“互不攻击”的约束准许进行深度优先搜索。4. 状态回溯与物理现场恢复Javacol[c] diag1[r c] diag2[rc] true; queens[r] c; dfs(...); col[c] diag1[r c] diag2[rc] false;执行先标记占用并递归回溯时复原标记。物理意义属于典型的隐式状态图回溯控制。在向下递归搜索子空间后必须在返回时撤销当前层的标记释放被占用的对角线和列以便后续其他分支能够重新试探该物理网格。四、 算法执行状态机步进示例以输入棋盘规模 n 4 为例展示算法在搜索首个合法方案[1, 3, 0, 2]时的状态机演进过程注皇后记录数组 queens 格式为[r0的列, r1的列, ...]步骤当前递归层级 (行 r)试探列 c状态判定与冲突核验执行的决策与物理剪枝动作全局调用栈及占位标记状态说明初始01检查 col[1], diag1[1], diag2[2] 均为 false放置皇后于 (0,1)标记对应一维数组为 truequeens[0] 1, 栈深: [0]113列 0,1,2 均因对角线或列冲突被拦截试探 3 通过放置皇后于 (1,3)标记对应一维数组为 truequeens[1] 3, 栈深: [0, 1]220列 1,2,3 冲突试探 0 通过放置皇后于 (2,0)标记对应一维数组为 truequeens[2] 0, 栈深: [0, 1, 2]332列 0,1,3 冲突试探 2 通过放置皇后于 (3,2)标记对应一维数组为 truequeens[3] 2, 栈深: [0, 1, 2, 3]44-满足 r 4触及退出基准条件提取 queens 数组生成棋盘字符串将方案存入答案列表并返回栈深: [0, 1, 2, 3] - 逐层回溯五、 源码实现import java.util.ArrayList; import java.util.Arrays; import java.util.List; class Solution { public ListListString solveNQueens(int n) { // 用于存储所有合法的棋盘布局方案 ListListString ans new ArrayList(); // 物理映射数组queens[i] 存储第 i 行皇后的列位置 int[] queens new int[n]; // 占位哈希标记哪些列已被皇后占用 boolean[] col new boolean[n]; // 占位哈希标记哪些主对角线r c已被占用大小为 2n - 1 boolean[] diag1 new boolean[2 * n - 1]; // 占位哈希标记哪些副对角线r - c n - 1已被占用大小为 2n - 1 boolean[] diag2 new boolean[2 * n - 1]; // 启动深度优先搜索回溯状态机从第 0 行开始递推 dfs(ans, queens, col, diag1, diag2, 0); return ans; } private void dfs(ListListString ans, int[] queens, boolean[] col, boolean[] diag1, boolean[] diag2, int r) { // 基准退出条件若行指针 r 越出边界说明全部行已安全放置完毕转化并存储当前合法布局 if (r col.length) { ListString path new ArrayList(); for (int c : queens) { char[] row new char[col.length]; Arrays.fill(row, .); row[c] Q; // 将指定位置改写为皇后字符 path.add(new String(row)); } ans.add(new ArrayList(path)); // 复制当前路径至结果集合 return; } // 迭代处理当前行 r 对应的每一个物理列位置 c for (int c 0; c col.length; c) { // 防溢出索引变换将副对角线差值偏移映射至正整数闭区间内 int rc r - c col.length - 1; // 安全核验网当前列、主对角线、副对角线必须均未被占用 if (!col[c] !diag1[r c] !diag2[rc]) { // 现场标记占用对应一维向量空间状态 col[c] diag1[r c] diag2[rc] true; queens[r] c; // 记录当前行摆放位置 // 向下递归探寻下一行皇后的安全分布点 dfs(ans, queens, col, diag1, diag2, r 1); // 现场恢复撤销标记支持后续的分支试探与物理重用 col[c] diag1[r c] diag2[rc] false; } } } }六、 复杂度分析1. 时间复杂度O(n!)分析在回溯搜索树的第一行中有 n 个位置可以尝试放置在第二行中由于列和对角线的冲突限制最多只能在剩余的 n-1 个位置中尝试第三行中最多有 n-2 个位置以此类推。在实际搜索过程中对角线占位哈希对搜索树进行了大面积的物理截断实际计算步数远小于 n!但其最坏渐近时间复杂度仍定性为 O(n!)。结论时间复杂度上限为 O(n!)达到了求解全排列及剪枝剪半问题的最优时间标准。2. 空间复杂度O(n)分析算法在执行期间仅申请了常数倍 n 规模的一维数组queens数组空间为 O(n)三个布尔哈希数组的总大小为 n (2n-1) (2n-1) 5n - 2属于严格的线性阶 O(n)。此外递归调用的最大深度受限于行数 n系统运行时的方法栈深度也为 O(n)。结论算法没有申请任何与指数解空间成正比的二维外部矩阵额外空间复杂度稳定控制在 O(n)。