279. 完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
解题思路: 此题有两种解法,即BFS和DP。先说BFS的解法,我们可以把完全平方数与它的分解的平方数看成一个图,确切的说看成一个多叉树,然后题目要求我们求组成完全平方数最少,那我们可以转化为找最短的一条路径,那我们自然会想到找迷宫的题,因此使用BFS最为合适,思路也比较直接和简单。请看代码。
- 解法一
class Solution {
public:
int numSquares(int n) {
if (n == 1) return 1;
int a = sqrt(n);
queue<int> q{{n}};
int res = 0;
while (!q.empty()) {
for (int i = q.size(); i > 0; --i) {
int tmp = q.front(); q.pop();
if (tmp == 0) return res;
for (int j = sqrt(tmp); j >= 1; --j) {
q.push(tmp - j * j);
}
}
++res;
}
return res;
}
};
其实这题我们也可以用动态规划解题。解动态规划的题的关键是找到动态转移方程,这题的动态转移方程是: d p ( i ) = m i n ( d p ( i − 1 2 ) , d p ( i − 2 2 ) , . . . , d p ( i − j 2 ) dp(i)=min(dp(i-1^2),dp(i-2^2),...,dp(i-j^2) dp(i)=min(dp(i−12),dp(i−22),...,dp(i−j2),其中 j 2 j^2 j2为最接近i的完全平方数。基本上到这里此题就可解了。
- 解法二
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 1);
for (int i = 1; i <= n; ++i) dp[i] = i;
for (int i = 1; i <= n; ++i) {
int mn = INT_MAX;
for (int j = sqrt(i); j >= 1; --j) {
mn = min(mn, dp[i - j * j]);
}
dp[i] = mn + 1;
}
return dp[n];
}
};
*动态规划+最优解的Tips:
这里在提一个动态规划解题的感受。解动态规划的题,尤其是解那个含最优解的题,比如这里取最小值(含比较大小),我们的每个节点的值并不是一开始就确定为最优值的,往往一开始赋的都是不太优的值,然后在遍历的过程中一遍一遍刷新所有节点的值,在这个刷新的过程中,所有的节点值会慢慢变为最优解。