【力扣100题】44.完全平方数

题目描述

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

完全平方数是一个整数,其值等于另一个整数的平方。例如 1、4、9、16 都是完全平方数,而 311 不是。

示例:

  • 输入:n = 12 → 输出:312 = 4 + 4 + 4
  • 输入:n = 13 → 输出:213 = 4 + 9

解题思路总览

方法 思路 时间复杂度 空间复杂度
动态规划 dp[i] 表示和为 i 的最少完全平方数个数,状态转移 dp[i] = min(dp[i], dp[i-j*j]+1) O(n√n) O(n)
数学公式 勒让德三平方定理,判断是否能表示为 1/2/3/4 个平方数之和 O(1) O(1)

本题采用动态规划方法。


完整代码

cpp 复制代码
class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j * j <= i; j++) {
                dp[i] = min(dp[i - j * j] + 1, dp[i]);
            }
        }
        return dp[n];
    }
};

算法流程图

复制代码
输入: n = 12

初始化:
  dp[0] = 0
  dp[1...12] = INT_MAX

i = 1:
  j = 1, j*j = 1 <= 1
    dp[1] = min(INT_MAX, dp[0]+1) = 1
  dp[1] = 1

i = 2:
  j = 1, j*j = 1 <= 2
    dp[2] = min(INT_MAX, dp[1]+1) = 2
  j = 2, j*j = 4 > 2, 退出
  dp[2] = 2

i = 3:
  j = 1, j*j = 1 <= 3
    dp[3] = min(INT_MAX, dp[2]+1) = 3
  j = 2, j*j = 4 > 3, 退出
  dp[3] = 3

i = 4:
  j = 1, j*j = 1 <= 4
    dp[4] = min(INT_MAX, dp[3]+1) = 4
  j = 2, j*j = 4 <= 4
    dp[4] = min(4, dp[0]+1) = 1
  dp[4] = 1

... (继续迭代直到 i = 12)

i = 12:
  j = 1: dp[12] = dp[11]+1 = 4
  j = 2: dp[12] = dp[8]+1 = 3
  j = 3: dp[12] = dp[3]+1 = min(3, 4) = 3
  j = 4: dp[12] = dp[-4]无效, 跳过 (j*j=16>12)

最终 dp[12] = 3
输出: 3

逐行解析

cpp 复制代码
vector<int> dp(n + 1, INT_MAX);

含义: 创建大小为 n+1 的数组,dp[i] 表示和为 i 的完全平方数的最少数量。初始化为 INT_MAX 表示尚未计算。

cpp 复制代码
dp[0] = 0;

含义: 基础情况,和为 0 需要 0 个完全平方数。

cpp 复制代码
for (int i = 1; i <= n; i++)

含义: 从 1 到 n 依次计算每个数的最少完全平方数个数。

cpp 复制代码
for (int j = 1; j * j <= i; j++)

含义: 枚举所有可能的完全平方数 j*j,其中 j 从 1 开始,直到 j*j 不超过 i

cpp 复制代码
dp[i] = min(dp[i], dp[i - j * j] + 1);

含义: 状态转移方程。如果从 i 中减去一个完全平方数 j*j,那么剩下的 i-j*j 需要 dp[i-j*j] 个平方数,再加上当前的 j*j,总共 dp[i-j*j]+1 个。取较小值更新 dp[i]


复杂度分析

复杂度 说明
时间复杂度 O(n√n) 外层循环 n 次,内层循环最多 √n 次(因为 j*j ≤ i)
空间复杂度 O(n) 需要大小为 n+1 的 dp 数组

面试追问 FAQ

问题 答案
为什么 dp[0] = 0 0 的完全平方数之和只能是 0,需要 0 个数字,这是动态规划的基础情况
能否用 BFS 解决? 可以,将 n 作为起点,每次减去一个完全平方数,层数即为最少数量
如何优化到 O(n)? 使用数学方法:勒让德三平方定理可 O(1) 判断,但实现复杂
完全平方数有哪些性质? 平方数 mod 4 结果为 0 或 1,可用于快速判断某个数是否为完全平方数
为什么内层循环是 j*j <= i 因为 j*j 作为被减数不能超过 i,否则 i-j*j 为负数

相关题目

题号 题目 难度 核心思路
279 完全平方数 中等 动态规划/BFS
322 零钱兑换 中等 完全背包
300 最长递增子序列 中等 动态规划
139 单词拆分 中等 完全背包

总结

要点 内容
核心思想 动态规划,枚举所有完全平方数作为最后一个加数
状态定义 dp[i] = 和为 i 的最少完全平方数个数
状态转移 dp[i] = min(dp[i], dp[i-j*j]+1)
边界条件 dp[0] = 0

相关推荐
血色橄榄枝5 小时前
基于用户注册信息的关键词检测挑战赛「Datawhale AI 夏令营」
人工智能·算法·机器学习
c238566 小时前
第二篇:《测试指挥官:可视化单题自测框架(含 assert 实操)》
java·数据库·c++·算法·安全性测试
六点_dn7 小时前
Linux学习笔记-printf命令
linux·运维·算法
遥感知识服务7 小时前
Sentinel-1 + DEM + FwDET + 随机森林:从快速水深初估到多因子误差修正
算法·随机森林·sentinel
来一碗刘肉面8 小时前
顺序表与链表的比较
数据结构·算法·链表
alphaTao8 小时前
LeetCode 每日一题 2026/7/13-2026/7/19
算法·leetcode
nnerddboy8 小时前
脑电信号处理实战 03 | 运动想象脑机接口入门:ERD/ERS、CSP 空间滤波与左右拳想象解码
算法·信号处理
QN1幻化引擎9 小时前
Dalin L — 我造了一门支持中文编程的语言,完整移植到 Rust 了
人工智能·算法·机器学习
Rainy Blue8839 小时前
C转C++速成
c语言·c++·算法
txzrxz9 小时前
二分图详解
数据结构·c++·算法·图论·深度优先搜索·二分图染色