leetcode——第279题——完全平方数

题目:
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

class Solution {
/*
将本题翻译为 完全背包问题:
完全平方数 就是物品,可以无条件使用
凑个整数 n 就是背包的最大容量为 n
问凑满这个背包 最少 有多少个物品。

i * i 表示第 i 个物品的重量 为 i*i
也就是 object[i] = i*i
求最少的问题,与322简直一模一样呐

动规五部曲:
1、确定 dp 数组以及下标的含义
dp[j] 和为 j 的完全平方数的最少数量为 dp[j]

2、确定递推公式
dp[j] = min(dp[j], dp[j - i * i])

3、初始化 dp 数组
dp[0] = 0
dp[j] : j 为其他数时,dp[j] = INT_MAX

4、确定遍历顺序
先物品或者先背包都可以,正序

这个题可以归约为零钱兑换,如果对 i*i 那部分有疑惑,可以先对输入 k 进行预处理,
将 k 转为 完全平方数的列表,然后这个题就完全与零钱兑换一模一样了,但是预处理
的效率会由于多一次for循环,相对直接在原地运算较低,但是是最容易想到的思路,
而且复杂度来说是一样的,可以对 ac 后的代码再进行优化,去掉预处理的 for 循环
*/
public:
    int numSquares(int n) {
        // dp[j] 意义:和为 j 的完全平方数的最少数量为 dp[j]
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;

        // // 方法一:先遍历物品,再遍历背包容量
        // // 注意这里的 物品重量是 i*i 因此循环终止条件要是 i*i <= n
        // for(int i = 1; i * i <= n; i++)
        // {
        //     // 这里的 j 为什么从 1 开始,是因为本题中的 object[i] = i
        //     for(int j = 1; j <= n; j++)
        //     {
        //     // 除了防止数据溢出的判断,
        //     // 还需加一个条件,就是判断 j - i * i >= 0 
        //     // 为了保证 背包容量 大于 物品重量
        //         if(j - i * i >= 0 && dp[j - i * i] != INT_MAX)
        //         {
        //             dp[j] = min(dp[j], 1 + dp[j - i * i]); 
        //         }
        //     }
        // }

        // 方法二:先遍历背包重量,在遍历物品
        for(int j = 0; j <= n; j++)
        {
            // for(int i = 1; i * i <= n; i++)
            // {
            //     // 注意这个 if 可以与 for 循环中的终止条件合并一下。
            //     if(j >= i * i)
            //     {
            //         // 刚刚把 dp[j - i * i] 错写成了 dp(j - i * i)
            //         dp[j] = min(dp[j], 1 + dp[j - i * i]); 
            //     }
            // }

            // 这里也可以写为:
            for(int i = 1; i * i <= j; i++)
            {
                dp[j] = min(dp[j], 1 + dp[j - i * i]);
            }
        }
        return dp[n];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值