题目链接
class Solution {
public:
int numSquares(int n) {
}
};
这题让求的是若干个平方数的和等于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;
}
};
该题目是一道典型的完全背包,设定一维数组 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];
}
};