LeetCode 51.N皇后

51. N皇后

51.N-Queens (Hard)

Leetcode / 力扣

题目描述

在 n*n 的矩阵中摆放 n 个皇后,并且每个皇后不能在同一行,同一列,同一对角线上,求所有的 n 皇后的解。

解题思路

这个问题本质上跟全排列问题差不多,决策树的每一层表示棋盘上的每一行;每个节点可以做出的选择是,在该行的任意一列放置一个皇后。

当 N = 8 时,就是八皇后问题,数学大佬高斯穷尽一生都没有数清楚八皇后问题到底有几种可能的放置方法,但是我们的算法只需要一秒就可以算出来所有可能的结果。

不过真的不怪高斯。这个问题的复杂度确实非常高,看看我们的决策树,虽然有 isValid 函数剪枝,但是最坏时间复杂度仍然是 O(N^(N+1)),而且无法优化。如果 N = 10 的时候,计算就已经很耗时了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class Solution {
private List<List<String>> res;
private static List<String> charToString(char[][] array) {
List<String> result = new LinkedList<>();
for (char[] chars : array) {
result.add(String.valueOf(chars));
}
return result;
}

/* 输入棋盘边长 n,返回所有合法的放置 */
public List<List<String>> solveNQueens(int n) {
if (n <= 0) return null;
res = new LinkedList<>();
// '.' 表示空,'Q' 表示皇后,初始化空棋盘
char[][] board = new char[n][n];
for (char[] chars : board){
Arrays.fill(chars, '.');
}
backtrack(board, 0);
return res;
}

/**
* 路径:board中小于row的那些行都已经成功放置了皇后
* 可选择列表: 第row行的所有列都是放置Q的选择
* 结束条件: row超过board的最后一行
*/
private void backtrack(char[][] board, int row) {
// 结束条件,构造输出
if (row == board.length) {
res.add(charToString(board));
return;
}
int n = board[row].length;
for (int col = 0; col < n; col++) {
// 排除不合法选择
if (!isValid(board, row, col)) continue;
// 做选择
board[row][col] = 'Q';
// 进入下一行决策
backtrack(board, row + 1);
// 撤销选择
board[row][col] = '.';
}
}

/* 是否可以在 board[row][col] 放置皇后? */
private boolean isValid(char[][] board, int row, int col) {
int rows = board.length;
// check is valid in col列
for (char[] chars : board) if (chars[col] == 'Q') return false;
// check is valide upright右上方
for (int i = row - 1, j = col + 1; i >= 0 && j < rows; i--, j++) {
if (board[i][j] == 'Q') return false;
}
// check is valide upleft左上方
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 'Q') return false;
}
return true;
}
}