279. 完全平方数
一看题目就觉得是完全背包,但是没想到怎么做。(建议复习这题的时候看看前面的dp汇总训练,完全背包来加深理解)
问题转换:(问题转换能力真的非常重要)
给你这些1,4,9,16....重量的物品 装满容量为n的背包,最少要用多少个物品。
看到这里,自己写一写代码试一试吧!
重点是每个物品怎么表示 第i个物品,容量是i*i
AC代码:
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1,0x3f3f3f3f);
dp[0]=0;
for(int i=1;i*i<=n;i++)
{
for(int j=i*i;j<=n;j++)
{
dp[j]=min(dp[j],dp[j-i*i]+1);
}
}
return dp[n];
}
};
dp[i][j]表示从前i个物品中选,容量为j时选的最少物品数量。
有dp[i][j]=min(dp[i-1][j] , dp[i-1][j-i*i]+1, dp[i-1][j-2*i*i] +2,。。。。。)
不选第i个物品. 第i个物品选一个. 第i个物品选2个
dp[i][j-i*i]=min(dp[i-1][j-i*i], dp[i-1][j-2*i*i]+1, dp[i-1][j-3*i*I]+2............)
不选第i个物品. 第i个物品选一个。 第i个物品选2个
综上,可以得到dp[i][j]=min(dp[i-1][j],dp[i][j-i*i]+1)
用滚动数组优化得到:dp[j]=min(dp[j],dp[j-i*i]+1). (第二层从小到大遍历)
还有一种思路,直接理解。`dp` 数组的含义是:`dp[j]` 表示构成数字 `j` 需要的最少的完全平方数的个数。例如,如果 `dp[12] = 3`,表示构成数字 12 需要最少 3 个完全平方数。
逐步走一遍算法:
1. **初始化**:
- `vector<int> dp(n + 1, 0x3f3f3f3f);` 初始化 `dp` 数组,将其设置为一个大值 `0x3f3f3f3f`,表示一个不可能的高值(可以视为无穷大)。
- `dp[0] = 0;` 表示构成 0 需要 0 个完全平方数。2. **动态规划过程**:
- 外层循环遍历所有可能的完全平方数 `i*i`。
- 内层循环遍历从当前完全平方数 `i*i` 到 `n` 的所有值 `j`,更新 `dp[j]` 的值。更新公式:`dp[j] = min(dp[j], dp[j - i*i] + 1);`
这表示:对于当前的 `j`,如果使用了完全平方数 `i*i`,那么 `dp[j]` 应该是 `dp[j - i*i]` 再加上 1。举个例子:
假设 `n = 12`,算法的执行过程如下:
1. 初始化:`dp = [0, 0x3f3f3f3f, 0x3f3f3f3f, ..., 0x3f3f3f3f]`。
2. 遍历完全平方数:
- `i = 1`(完全平方数是 1):
- `j = 1`:`dp[1] = min(dp[1], dp[1-1*1] + 1) = min(0x3f3f3f3f, 0 + 1) = 1`
- `j = 2`:`dp[2] = min(dp[2], dp[2-1*1] + 1) = min(0x3f3f3f3f, 1 + 1) = 2`
- `j = 3`:`dp[3] = min(dp[3], dp[3-1*1] + 1) = min(0x3f3f3f3f, 2 + 1) = 3`
- ...
- `j = 12`:`dp[12] = min(dp[12], dp[12-1*1] + 1) = min(0x3f3f3f3f, 11 + 1) = 12`
- `i = 2`(完全平方数是 4):
- `j = 4`:`dp[4] = min(dp[4], dp[4-2*2] + 1) = min(4, 0 + 1) = 1`
- `j = 5`:`dp[5] = min(dp[5], dp[5-2*2] + 1) = min(5, 1 + 1) = 2`
- `j = 6`:`dp[6] = min(dp[6], dp[6-2*2] + 1) = min(6, 2 + 1) = 3`
- ...
- `j = 12`:`dp[12] = min(dp[12], dp[12-2*2] + 1) = min(12, 3 + 1) = 4`
- `i = 3`(完全平方数是 9):
- `j = 9`:`dp[9] = min(dp[9], dp[9-3*3] + 1) = min(3, 0 + 1) = 1`
- `j = 10`:`dp[10] = min(dp[10], dp[10-3*3] + 1) = min(4, 1 + 1) = 2`
- `j = 11`:`dp[11] = min(dp[11], dp[11-3*3] + 1) = min(5, 2 + 1) = 3`
- `j = 12`:`dp[12] = min(dp[12], dp[12-3*3] + 1) = min(4, 3 + 1) = 4`最终 `dp[12]` 的值为 3,这意味着构成数字 12 需要最少 3 个完全平方数。