Skip to content

Commit a7f4658

Browse files
committed
Update 0279. 完全平方数.md
1 parent 1d40dbf commit a7f4658

File tree

1 file changed

+57
-21
lines changed

1 file changed

+57
-21
lines changed

Solutions/0279. 完全平方数.md

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,54 +5,90 @@
55

66
## 题目大意
77

8-
给定一个正整数 n,找到若干个完全平方数(比如 1,4,9,16,...),使得它们的和等于 n。要求返回和为 n 的完全平方数的最小数量。
8+
**描述**:给定一个正整数 `n`。从中找到若干个完全平方数(比如 `1``4``1``16` ...),使得它们的和等于 `n`
9+
10+
**要求**:返回和为 `n` 的完全平方数的最小数量。
11+
12+
**说明**
13+
14+
- $1 \le n \le 10^4$。
15+
16+
**示例**
17+
18+
```Python
19+
输入:n = 12
20+
输出:3
21+
解释:12 = 4 + 4 + 4
22+
23+
24+
输入:n = 13
25+
输出:2
26+
解释:13 = 4 + 9
27+
```
928

1029
## 解题思路
1130

12-
对于小于 n 的完全平方数,直接暴力枚举所有可能的组合,并且找到平方数个数最小的一个。
31+
对于小于 `n` 的完全平方数,直接暴力枚举所有可能的组合,并且找到平方数个数最小的一个。
1332

14-
并且对于所有小于 n 的完全平方数(k = 1,4,9,16,...),存在公式 $ans(n) = min(ans(n-k) + 1),k = 1,4,9,16,...$
33+
并且对于所有小于 `n` 的完全平方数(`k = 1, 4, 9, 16, ...`),存在公式 $ans(n) = min(ans(n - k) + 1),k = 1,4,9,16,...$
1534

16-
即: **n 的完全平方数的最小数量** 等于 **n - k 的完全平方数的最小数量 + 1**
35+
即: **n 的完全平方数的最小数量 == n - k 的完全平方数的最小数量 + 1**
1736

18-
可以转为递归解决这个问题。但是因为重复计算了中间解,会产生堆栈溢出。
37+
我们可以使用递归解决这个问题。但是因为重复计算了中间解,会产生堆栈溢出。
1938

20-
怎么解决重复计算问题和避免堆栈溢出
39+
那怎么解决重复计算问题和避免堆栈溢出
2140

22-
将 n 作为根节点,构建一棵多叉数。从 n 节点出发,如果一个小于 n 的数刚好与 n 相差一个平方数,则以该数为值构造一个节点,与 n 相连
41+
我们可转换一下思维
2342

24-
那么求解和为 n 的完全平方数的最小数量就变成了求解这棵树从 n 节点到 0 节点的最短路径,或者说数的最小深度。
43+
1.`n` 作为根节点,构建一棵多叉数。
44+
2.`n` 节点出发,如果一个小于 `n` 的数刚好与 `n` 相差一个平方数,则以该数为值构造一个节点,与 `n` 相连。
2545

26-
首先,我们将小于 n 的平方数放入数组中。然后使用「广度优先搜索」的方式,每次从当前节点值减去一个平方数,将减完的数加入队列
46+
那么求解和为 `n` 的完全平方数的最小数量就变成了求解这棵树从 `n` 节点到 `0` 节点的最短路径,或者说数的最小深度
2747

28-
- 如果此时的数等于 0,则满足题意,返回层数。
29-
- 如果此时的数不等于 0,则将其加入队列,继续查找。
48+
这个过程可以通过广度优先搜索来做。
3049

31-
但是还有个问题:如何减少重复计算的次数。
50+
### 思路 1:广度优先搜索
3251

33-
我们可以使用一个 set 集合,来消除同一层中相同的数,这样就减少了计算次数。
52+
1. 定义 `visited` 为标记访问节点的 set 集合变量,避免重复计算。定义 `queue` 为存放节点的队列。使用 `count` 表示和为 `n` 的完全平方数的最小数量。
53+
2. 首先,我们将 `n` 标记为已访问,即 `visited.add(n)`。并将其加入队列 `queue` 中,即 `queue.append(n)`
54+
3.`count``1`,表示最小深度加 `1`。然后依次将队列中的节点值取出。
55+
4. 对于取出的节点值 `value`,遍历可能出现的平方数(即遍历 $[1, \sqrt{value} + 1]$ 中的数)。
56+
5. 每次从当前节点值减去一个平方数,并将减完的数加入队列。
57+
1. 如果此时的数等于 `0`,则满足题意,返回层数。
58+
2. 如果此时的数不等于 `0`,则将其加入队列,继续查找。
3459

35-
## 代码
60+
### 思路 1:代码
3661

3762
```Python
3863
class Solution:
3964
def numSquares(self, n: int) -> int:
4065
if n == 0:
4166
return 0
42-
queue = collections.deque([n])
67+
4368
visited = set()
44-
level = 0
69+
queue = collections.deque([])
70+
71+
visited.add(n)
72+
queue.append(n)
73+
74+
count = 0
4575
while queue:
46-
level += 1
76+
// 最少步数
77+
count += 1
4778
size = len(queue)
4879
for _ in range(size):
49-
top = queue.pop()
50-
for i in range(1, int(math.sqrt(top)) + 1):
51-
x = top - i * i
80+
value = queue.pop()
81+
for i in range(1, int(math.sqrt(value)) + 1):
82+
x = value - i * i
5283
if x == 0:
53-
return level
84+
return count
5485
if x not in visited:
5586
queue.appendleft(x)
5687
visited.add(x)
5788
```
5889

90+
### 思路 1:复杂度分析
91+
92+
- **时间复杂度**:$O(n \times \sqrt{n})$。
93+
- **空间复杂度**:$O(n)$。
94+

0 commit comments

Comments
 (0)