【Hot 100 刷题计划】 LeetCode 279. 完全平方数 | C++ 动态规划 (完全背包)

LeetCode 279. 完全平方数

📌 题目描述

题目级别:中等

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

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

  • 示例 1:

    输入:n = 12

    输出:3

    解释:12 = 4 + 4 + 4

  • 示例 2:

    输入:n = 13

    输出:2

    解释:13 = 4 + 9


💡 破题思路:动态规划的完全背包模型

这道题本质上是一个完全背包问题的变形:

  • 背包容量 :数字 n
  • 物品 :所有的完全平方数(1,4,9,16...1, 4, 9, 16...1,4,9,16...)。
  • 物品重量:完全平方数的数值。
  • 物品价值:数量统统算作 1 个(因为题目要求"最少数量")。
  • 特殊限制:每个物品可以无限次使用。

状态定义:

定义 dp[i] 为:和为 i 的完全平方数的最少数量。

状态转移方程:

对于当前的数字 i,它可以由之前的某个数字加上一个"完全平方数 j×jj \times jj×j"组合而来。

所以我们只需要回头看看之前的状态 dp[i - j*j],然后在这个基础上加 1(也就是加上当前这个完全平方数)。

为了求最少数量,我们在所有可能的回头路径中取最小值:

dp[i] = min(dp[i], dp[i - j * j] + 1)

巧妙的初始化:

  • dp[0] = 0:凑成 0 需要 0 个数。
  • 对于其他的 dp[i],我们需要初始化为一个极大值。这里非常巧妙地初始化为 n + 1。因为即使全用 1 来凑,最多也只需要 n 个数,所以 n + 1 在这里就起到了"无穷大"的作用,同时完美避免了使用 INT_MAX 时发生 INT_MAX + 1 导致的整数溢出问题!

💻 C++ 代码实现

cpp 复制代码
class Solution {
public:
    int numSquares(int n) {
        // 使用变长数组 (或可以替换为 vector<int> dp(n + 1, n + 1))
        int dp[n + 10];
        
        dp[0] = 0;
        // 巧妙初始化为 n + 1,相当于安全版的无穷大
        for (int i = 1; i <= n; i ++ ) dp[i] = n + 1;

        // 遍历背包容量 (从 1 到 n)
        for (int i = 1; i <= n; i ++ )
        {
            // 遍历物品 (完全平方数 j*j)
            for (int j = 1; j * j <= i; j ++ )
            {
                // 状态转移:取当前值与"刨除完全平方数后剩余值的最少数量 + 1"的较小者
                dp[i] = min(dp[i], dp[i - j * j] + 1);
            }
        }

        return dp[n];
    }
};
相关推荐
倒头就睡的小比特1 天前
算法竞赛C++常用的STL
c++·算法
weilx12341 天前
C++笔记-文件IO-<fcntl.h>
c++
Smileyqp沛沛1 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车1 天前
C/C++ 为什么需要编译器?
开发语言·c++
旖旎夜光1 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
吞下星星的少年·-·1 天前
C++ 萌新语法入门篇
c++·算法比赛
霍霍的袁1 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
another heaven1 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
程序猿编码1 天前
告别改源码适配模型:纯 C++ 可配置 LLM 推理引擎,全格式全结构兼容
c++·大模型·llm·推理引擎
此生决int1 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++