hot 100

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 个完全平方数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值