Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f6b8b7f

Browse files
committed
Create 0052. N皇后 II.md
1 parent 604d345 commit f6b8b7f

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

‎Solutions/0052. N皇后 II.md‎

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# [0052. N皇后 II](https://leetcode.cn/problems/n-queens-ii/)
2+
3+
- 标签:回溯
4+
- 难度:困难
5+
6+
## 题目大意
7+
8+
**描述**:给定一个整数 `n`
9+
10+
**要求**:返回「`n` 皇后问题」不同解决方案的数量。
11+
12+
**说明**:
13+
14+
- **n 皇后问题**:将 `n` 个皇后放置在 `n * n` 的棋盘上,并且使得皇后彼此之间不能攻击。
15+
- **皇后彼此不能相互攻击**:指的是任何两个皇后都不能处于同一条横线、纵线或者斜线上。
16+
- 1ドル \le n \le 9$。
17+
18+
**示例**:
19+
20+
```Python
21+
输入:n = 4
22+
输出:2
23+
解释:如下图所示,4 皇后问题存在两个不同的解法。
24+
```
25+
26+
![](https://assets.leetcode.com/uploads/2020/11/13/queens.jpg)
27+
28+
## 解题思路
29+
30+
### 思路 1:回溯算法
31+
32+
和「[51. N 皇后 - 力扣](https://leetcode.cn/problems/n-queens/)」做法一致。区别在于「[51. N 皇后 - 力扣](https://leetcode.cn/problems/n-queens/)」需要返回所有解决方案,而这道题只需要得到所有解决方案的数量即可。下面来说一下这道题的解题思路。
33+
34+
我们可以按照行序来放置皇后,也就是先放第一行,再放第二行 ...... 一直放到最后一行。
35+
36+
对于 `n * n` 的棋盘来说,每一行有 `n` 列,也就有 `n` 种放法可供选择。我们可以尝试选择其中一列,查看是否与之前放置的皇后有冲突,如果没有冲突,则继续在下一行放置皇后。依次类推,直到放置完所有皇后,并且都不发生冲突时,就得到了一个合理的解。
37+
38+
并且在放置完之后,通过回溯的方式尝试其他可能的分支。
39+
40+
下面我们根据回溯算法三步走,写出对应的回溯算法。
41+
42+
1. **明确所有选择**:根据棋盘中当前行的所有列位置上是否选择放置皇后,画出决策树,如下图所示。
43+
44+
- ![](https://qcdn.itcharge.cn/images/20220426095225.png)
45+
46+
2. **明确终止条件**:
47+
48+
- 当遍历到决策树的叶子节点时,就终止了。也就是在最后一行放置完皇后时,递归终止。
49+
50+
3. **将决策树和终止条件翻译成代码:**
51+
52+
1. 定义回溯函数:
53+
54+
- 首先我们先使用一个 `n * n` 大小的二维矩阵 `chessboard` 来表示当前棋盘,`chessboard` 中的字符 `Q` 代表皇后,`.` 代表空位,初始都为 `.`
55+
- 然后定义回溯函数 `backtrack(chessboard, row): ` 函数的传入参数是 `chessboard`(棋盘数组)和 `row`(代表当前正在考虑放置第 `row` 行皇后),全局变量是 `ans`(所有可行方案的数量)。
56+
- `backtrack(chessboard, row):` 函数代表的含义是:在放置好第 `row` 行皇后的情况下,递归放置剩下行的皇后。
57+
2. 书写回溯函数主体(给出选择元素、递归搜索、撤销选择部分)。
58+
- 枚举出当前行所有的列。对于每一列位置:
59+
- 约束条件:定义一个判断方法,先判断一下当前位置是否与之前棋盘上放置的皇后发生冲突,如果不发生冲突则继续放置,否则则继续向后遍历判断。
60+
- 选择元素:选择 `row, col` 位置放置皇后,将其棋盘对应位置设置为 `Q`
61+
- 递归搜索:在该位置放置皇后的情况下,继续递归考虑下一行。
62+
- 撤销选择:将棋盘上 `row, col` 位置设置为 `.`
63+
64+
### 思路 1:代码
65+
66+
```Python
67+
class Solution:
68+
# 判断当前位置 row, col 是否与之前放置的皇后发生冲突
69+
def isValid(self, n: int, row: int, col: int, chessboard: List[List[str]]):
70+
for i in range(row):
71+
if chessboard[i][col] == 'Q':
72+
return False
73+
74+
i, j = row - 1, col - 1
75+
while i >= 0 and j >= 0:
76+
if chessboard[i][j] == 'Q':
77+
return False
78+
i -= 1
79+
j -= 1
80+
i, j = row - 1, col + 1
81+
while i >= 0 and j < n:
82+
if chessboard[i][j] == 'Q':
83+
return False
84+
i -= 1
85+
j += 1
86+
87+
return True
88+
89+
def totalNQueens(self, n: int) -> int:
90+
chessboard = [['.' for _ in range(n)] for _ in range(n)] # 棋盘初始化
91+
92+
ans = 0
93+
def backtrack(chessboard: List[List[str]], row: int): # 正在考虑放置第 row 行的皇后
94+
if row == n: # 遇到终止条件
95+
nonlocal ans
96+
ans += 1
97+
return
98+
99+
for col in range(n): # 枚举可放置皇后的列
100+
if self.isValid(n, row, col, chessboard): # 如果该位置与之前放置的皇后不发生冲突
101+
chessboard[row][col] = 'Q' # 选择 row, col 位置放置皇后
102+
backtrack(chessboard, row + 1) # 递归放置 row + 1 行之后的皇后
103+
chessboard[row][col] = '.' # 撤销选择 row, col 位置
104+
105+
backtrack(chessboard, 0)
106+
107+
return ans
108+
```
109+
110+
### 思路 1:复杂度分析
111+
112+
- **时间复杂度**:$O(n!),ドル其中 $n$ 是皇后数量。
113+
- **空间复杂度**:$O(n^2),ドル其中 $n$ 是皇后数量。递归调用层数不会超过 $n,ドル每个棋盘的空间复杂度为 $O(n^2),ドル所以空间复杂度为 $O(n^2)$。

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /