LeetCode 力扣热题100 完全平方数

问题分析

题目是 完全平方数(Perfect Squares):

给定一个正整数 n,找到最少的完全平方数的个数,使它们的和等于 n。

例如:

• n = 12 → 12 = 4 + 4 + 4 → 最少 3 个完全平方数(3^2 不行,因为 9+3 不是完全平方数)。

• n = 13 → 13 = 4 + 9 → 最少 2 个完全平方数。

解题思路

1. 动态规划 (Dynamic Programming)

定义状态

• dp[i] 表示最少使用多少个完全平方数来表示 i。

状态转移方程

• 对于任意 i,可以由一个更小的数 i - j^2 加上 j^2 来得到:

• 其中 j^2 是小于等于 i 的完全平方数

初始化

• dp[0] = 0,因为 0 需要 0 个完全平方数。

• dp[i] 默认初始化为 i,因为 i 最坏情况是 1 + 1 + ... + 1(全是 1 的平方)。

最终答案

• dp[n] 即为 n 所需的最少完全平方数个数。

代码解析

class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1);
        for(int i = 1; i <= n; i++) {
            dp[i] = i;  // 最坏情况:全是 1
            for(int j = 1; i - j * j >= 0; j++) {  
                dp[i] = min(dp[i], dp[i - j * j] + 1); // 核心状态转移方程
            }
        }
        return dp[n]; 
    }
};

运行步骤

假设输入 n = 12,动态规划表 dp 变化如下:

i

dp[i] 计算方式

dp[i] 结果

1

dp[1] = min(1, dp[0] + 1) = 1

1

2

dp[2] = min(2, dp[1] + 1) = 2

2

3

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

3

4

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

1

5

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

2

6

dp[6] = min(6, dp[2] + 1) = 3

3

7

dp[7] = min(7, dp[3] + 1) = 4

4

8

dp[8] = min(8, dp[4] + 1) = 2

2

9

dp[9] = min(9, dp[0] + 1) = 1

1

10

dp[10] = min(10, dp[6] + 1) = 2

2

11

dp[11] = min(11, dp[7] + 1) = 3

3

12

dp[12] = min(12, dp[8] + 1) = 3

3

最终 dp[12] = 3,即 12 = 4 + 4 + 4,需要 3 个完全平方数。

时间复杂度

外层循环:i 从 1 到 n,O(n)

内层循环:j^2 ≤ i,最多 O(√n)

总时间复杂度:

空间复杂度:O(n)(dp 数组占用的空间)。

优化方案

可以用 四平方定理 + 贪心 + BFS 进一步优化:

1. 四平方和定理(拉格朗日定理):任何正整数 n 至多由 4 个完全平方数组成。

• 如果 n 是完全平方数,直接返回 1。

• 如果 n 可以拆成两个完全平方数,返回 2。

• 如果 n 满足 n = 4^a × (8b + 7),返回 4。

• 否则返回 3。

class Solution {
public:
    bool isPerfectSquare(int n) {
        int sq = sqrt(n);
        return sq * sq == n;
    }
    
    int numSquares(int n) {
        // 1. 如果是完全平方数,直接返回 1
        if (isPerfectSquare(n)) return 1;
        
        // 2. 检查是否能由两个完全平方数组成
        for (int i = 1; i * i <= n; i++) {
            if (isPerfectSquare(n - i * i)) return 2;
        }

        // 3. 如果 n 满足 4^a * (8b + 7),则返回 4
        while (n % 4 == 0) n /= 4; // 去掉 4^a
        if (n % 8 == 7) return 4;

        // 4. 否则返回 3
        return 3;
    }
};

优化后的时间复杂度

检查是否是完全平方数: O(1)

检查是否由两个平方数组成: O(√n)

四平方定理判定: O(log n)

最终优化后的时间复杂度:O(√n),比 O(n√n) 提高了很多。

总结

1. 动态规划解法(O(n√n))适用于一般情况:

• dp[i] = min(dp[i], dp[i - j^2] + 1)

• 通过遍历 1, 4, 9, ... 更新 dp。

2. 数学优化(O(√n))基于 四平方定理

• 直接判断 n 是否满足特殊情况,避免 DP 计算。

在实际应用中:

n 比较小(如 ≤ 10^4)时,DP 适用

n 很大(如 10^9),用数学方法更快

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值