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 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)

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