Skip to content

完全平方数

LeetCode 官方题目链接

题目描述

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

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

示例 1:

text
输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4

示例 2:

text
输入:n = 13
输出:2
解释:13 = 4 + 9

思路拆解

这是一道经典的动态规划问题,类似于背包问题。

动态规划

  1. 定义状态dp[i] 表示和为 i 的完全平方数的最少数量。
  2. 状态转移方程
    • 对于每个 i,我们可以枚举最后一个完全平方数 j*j
    • 状态转移为:dp[i] = min(dp[i - j*j]) + 1,其中 1 <= j*j <= i
    • 也就是说,当前的数量等于「减去一个平方数后的数量」加 1。
  3. 初始条件
    • dp[0] = 0
    • 其他位置初始化为无穷大。

代码实现

javascript
/**
 * @param {number} n
 * @return {number}
 */
var numSquares = function(n) {
    const dp = new Array(n + 1).fill(Infinity);
    dp[0] = 0;

    for (let i = 1; i <= n; i++) {
        // 枚举所有可能的平方数 j*j
        for (let j = 1; j * j <= i; j++) {
            dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
        }
    }

    return dp[n];
};

运行演示

假设 n = 5

  1. 初始化 dp = [0, Inf, Inf, Inf, Inf, Inf]
  2. i = 1: j=1 (1*1<=1), dp[1] = min(Inf, dp[0]+1) = 1dp=[0, 1, ...]
  3. i = 2: j=1 (1*1<=2), dp[2] = min(Inf, dp[1]+1) = 2dp=[0, 1, 2, ...]
  4. i = 3: j=1 (1*1<=3), dp[3] = min(Inf, dp[2]+1) = 3dp=[0, 1, 2, 3, ...]
  5. i = 4:
    • j=1 (1*1<=4), dp[4] = min(Inf, dp[3]+1) = 4
    • j=2 (2*2<=4), dp[4] = min(4, dp[0]+1) = 1dp=[0, 1, 2, 3, 1, ...]
  6. i = 5:
    • j=1 (1*1<=5), dp[5] = min(Inf, dp[4]+1) = 2
    • j=2 (2*2<=5), dp[5] = min(2, dp[1]+1) = 2dp=[0, 1, 2, 3, 1, 2]

返回 2 (4+1)。

复杂度分析

  • 时间复杂度:$O(n \sqrt{n})$。外层循环 n 次,内层循环 \sqrt{n} 次。
  • 空间复杂度:$O(n)$,需要一个数组存储状态。

Power by VitePress