1. 完全平方数问题解析
这道力扣hot100题目要求我们找到组成给定整数n所需的最少完全平方数数量。乍看简单,实则暗藏玄机。我第一次遇到这个问题时,直觉告诉我应该从最大的平方数开始尝试,但实际操作中发现这种贪心思路并不总是最优解。比如n=12时,最大的平方数是9,但12=9+1+1+1需要4个数,而最优解是12=4+4+4只需要3个数。
这个问题本质上属于完全背包问题的变种。我们可以把每个完全平方数看作一种"物品",其"重量"就是平方数本身,背包容量是n,每种物品可以无限取用。我们的目标是恰好装满背包,且使用的物品数量最少。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动态规划解法详解
2.1 状态定义与转移方程
定义dp[i][j]表示使用前i个完全平方数(即1²,2²,...,i²)组成和为j所需的最少数量。状态转移需要考虑两种情况:
- 不使用i²:dp[i][j] = dp[i-1][j]
- 使用i²:dp[i][j] = dp[i][j-i²] + 1(前提是j≥i²)
取两者中的较小值作为最终结果。这个转移方程体现了动态规划的核心思想——将大问题分解为子问题。
注意:初始化时dp[0][0]=0,表示用0个数组成0需要0个数;dp[0][j]=∞(j>0)表示不可能用0个数组成正数。
2.2 空间优化技巧
二维DP会消耗O(n√n)空间,实际上可以优化为一维数组:
java复制public int numSquares(int n) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i * i <= n; i++) {
int square = i * i;
for (int j = square; j <= n; j++) {
if (dp[j - square] != Integer.MAX_VALUE) {
dp[j] = Math.min(dp[j], dp[j - square] + 1);
}
}
}
