279. 完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,149 和 16 都是完全平方数,而 3 和 11 不是。

//第一种方法:构建nums数组(完全平方数数组),先遍历物品再遍历背包
class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;
        int target = (int)sqrt(n) + 1;
        vector<int> nums(target);
        for (int i = 0; i < nums.size() ; i++){
            nums[i] = i * i;
        }
        for (int i = 1; i < nums.size(); i++){
            for (int j = nums[i]; j <= n; j++){
                if (dp[j - nums[i]] != INT_MAX)
                dp[j] = min(dp[j], dp[j - nums[i]] + 1);
            }
        }
        return 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];
    }
};
// 第三种方法,先遍历物品,再遍历背包
class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 1; i * i <= n; i++) { // 遍历物品
            for (int j = i * i; j <= n; j++) { // 遍历背包
                dp[j] = min(dp[j - i * i] + 1, dp[j]);
            }
        }
        return dp[n];
    }
};

 

动规五部曲分析如下:

1.确定dp数组(dp table)以及下标的含义

dp[j]:和为j的完全平方数的最少数量为dp[j]

2.确定递推公式

dp[j] 可以由dp[j - i * i]推出, dp[j - i * i] + 1 便可以凑成dp[j]。

此时我们要选择最小的dp[j],所以递推公式:dp[j] = min(dp[j - i * i] + 1, dp[j]);

3.dp数组如何初始化

dp[0]表示 和为0的完全平方数的最小数量,那么dp[0]一定是0。

从递归公式dp[j] = min(dp[j - i * i] + 1, dp[j]);中可以看出每次dp[j]都要选最小的,所以非0下标的dp[j]一定要初始为最大值,这样dp[j]在递推的时候才不会被初始值覆盖

4.确定遍历顺序

我们知道这是完全背包,

如果求组合数就是外层for循环遍历物品,内层for遍历背包。

如果求排列数就是外层for遍历背包,内层for循环遍历物品。

所以本题外层for遍历背包,内层for遍历物品,还是外层for遍历物品,内层for遍历背包,都是可以的!

5.举例推导dp数组

已输入n为5例,dp状态图如下:

279.完全平方数

dp[0] = 0 dp[1] = min(dp[0] + 1) = 1 dp[2] = min(dp[1] + 1) = 2 dp[3] = min(dp[2] + 1) = 3 dp[4] = min(dp[3] + 1, dp[0] + 1) = 1 dp[5] = min(dp[4] + 1, dp[1] + 1) = 2

最后的dp[n]为最终结果。

 参考:代码随想录 (programmercarl.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完全平方数是对某个整数的平方结果,例如4(2^2)、9(3^2)等。在数学上,对于任意正整数n,如果存在另一个整数m使得m * m = n,则称n为完全平方数。 在 C++ 中处理完全平方数数对(假设这里指的是寻找两个整数,它们各自的平方相加等于目标值),我们可以创建一个函数,该函数接收一个整数作为输入,并尝试找到所有满足条件的整数组合。下面是具体的实现: ```cpp #include <iostream> #include <vector> using namespace std; void findSquarePairs(int targetSum) { for (int i = 0; i <= sqrt(targetSum); ++i) { // 避免不必要的循环迭代 int squareRoot = i * i; if (squareRoot > targetSum) break; // 如果当前平方根已经大于targetSum,则跳出循环 int otherPart = targetSum - squareRoot; int squareRootOfOtherPart = sqrt(otherPart); // 检查otherPart是否是一个完全平方数 if(squareRootOfOtherPart == floor(sqrt(otherPart))) { cout << "一对完全平方数:" << i << "^2 + " << squareRootOfOtherPart << "^2 = " << targetSum << endl; } } } // 使用示例 int main() { int target = 25; findSquarePairs(target); return 0; } ``` 在这个例子中,`findSquarePairs` 函数首先遍历小于或等于 `sqrt(targetSum)` 的数字,然后计算出剩余部分是否也是一个完全平方数。如果是的话,就找到了一组符合条件的数对。 --- 相关问题 --- 1. 这种方法的时间复杂度是多少?如何优化? 2. 如果目标值很大,那么如何减少内存消耗? 3. 对于负数或零的情况,这个算法应该如何修改?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值