题目
代码
class Solution {
public:
int numSquares(int n) {
}
};
方法一:BFS
分析
这题让求的是若干个平方数的和等于n,并且平方数的个数最少。首先我们可以将题目想象成为一颗根节点为 n n n 的多叉树,树的每子节点、叶子节点的值都是小于父节点数值的平方数 y ( y 2 ≤ n ) y(y^2 \leq n) y(y2≤n) 的平方和,用BFS广度优先搜索寻找 y 2 = n y^2 = n y2=n 的结点,此时的树深度 d e p t h depth depth 即为 n n n 的完全平方数的最小数量。
代码
class Solution {
public:
int numSquares(int n) {
unordered_set<int> visited;
queue<int> Q;
int ans = 1;
Q.push(n);
while(Q.size()) {
int cur = Q.size();
while(cur--) {
int x = Q.front();
Q.pop();
for(int y = (int)sqrt(x); y > 0; y--) {
int t = x - y * y;
if(t == 0) return ans;
if(!visited.count(t)) {
visited.insert(t);
Q.push(t);
}
}
}
ans++;
}
return 0;
}
};
复杂度分析
- 时间复杂度: O ( V + E ) O(V+E) O(V+E),其中 V V V 是多叉树中节点的数量, E E E 是多叉树中边的数量。
- 空间复杂度: O ( V ) O(V) O(V),其中 V V V 是多叉树中节点的数量,实现BFS需要最多需要 V V V 的队列 Q Q Q。
方法二:一维动态规划
分析
该题目是一道典型的完全背包,设定一维数组
d
p
[
i
]
dp[i]
dp[i] 表示构成
i
i
i 的完全平方数的最少数量,当
i
=
0
i = 0
i=0 时,只有一种情况,即
d
p
[
0
]
=
0
dp[0] = 0
dp[0]=0,因为本题目是找最小值,因此其余初始值为
I
N
T
_
M
A
X
INT\_MAX
INT_MAX。我们可以先使用数字
j
(
j
2
≤
i
)
j \ (j^2 \leq i)
j (j2≤i) 来依次遍历所有解,状态转移方程可表示为:
d
p
[
i
]
=
m
i
n
(
d
p
[
i
−
j
2
]
+
1
,
d
p
[
i
]
)
dp[i] = min(dp[i - j^2] + 1, \ dp[i])
dp[i]=min(dp[i−j2]+1, dp[i]) 问题答案为:
d
p
[
n
]
dp[n]
dp[n]
代码
class Solution {
public:
int numSquares(int n) {
vector<int> dp (n + 1, INT_MAX);
dp[0] = 0;
for(int i = 0; i <= n; i++) { // 遍历背包
for(int j = 1; j * j <= i; j++) { // 遍历物品
dp[i] = min(dp[i - j * j] + 1, dp[i]);
}
}
return dp[n];
}
};
复杂度分析
- 时间复杂度: O ( n n ) O(n \sqrt{n}) O(nn),其中 n n n 是给定数值, n \sqrt{n} n 是 j j j 的循环次数。
- 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是给定数值,实现动态规划需要创建 n n n 的一维数组 d p dp dp。