LeetCode 279. 完全平方数

LeetCode 279. 完全平方数

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

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= n <= 104

思路

  • 找到 n 之前最大的一个完全平方数 j(j*j<=i),记为一个个数;那么 还剩 n-j*j 需要继续拼凑。也就是说只要将 n-j*j 的解 dp[n-j*j] 加上上面 j*j 所占的那个1,就是最终解,也是最少的。
  • 注意:dp数组初始化时,赋值只要是 比n大的任意数 都可以,比如 dp[i] = n+1 或 dp[i]=math.MaxInt32 ...
    因为最终的dp方程 dp[i] = min(dp[i], dp[i-j*j] + 1) 中是要求min较小值
    其中 dp[i-j*j] + 1 只有跟一个 比n大的任意数dp[i] 相比,才能保证 dp[i-j*j] + 1 的值相对较小,从而获取到较小值:dp[i-j*j] + 1
  • 背包问题 更多可参考 LeetCode题解

时间复杂度

O(nn),其中 n 为给定的正整数。外循环时间复杂度为O(n),内循环的时间复杂度为 O(n),因此总时间复杂度为 O(nn)。

空间复杂度

O(n),dp数组所需。

// 理解:找到n之前最大的一个完全平方数j(j*j<=n),记为一个个数;那么 还剩n-j*j需要继续拼凑。也就是说只要将n-j*j的解dp[n-j*j] 加上上面j*j所占的那个1,就是n的解,这就是最短的。

func numSquares(n int) int {
    dp := make([]int, n+1) // 下标从0开始
    dp[0] = 0       // 题目要求从1的平方开始,所以0的情况可忽略
    
    // 初始化dp数组,此处注释,因为此步骤可以合并到下面的for循环中
    // for i := 1; i <= n; i++ {
    //     dp[i] = n+1 // dp[i]一开始全部都初始化为了n+1,比要求的n还大
    // }

    for i := 1; i <= n; i++ { // 当前循环中,需要组合的完全平方数为n
        dp[i] = n+1
        for j := 1; j*j <= i; j++ {
            // j从1开始,j*j不断增大,因此 diff=i-j*j 最终可以保证差值最小
            // +1:且j*j本身也是组成目标和n的其中一个完全平方数。
            // 比如:dp[13]=min(dp[13], dp[13-1*1] + 1), dp[13]=min(dp[13], dp[13-2*2] + 1), dp[13]=min(dp[13], dp[13-3*3] + 1)...
            dp[i] = min(dp[i], dp[i-j*j] + 1) 
        }
    }

    return dp[n]
}

func min(a, b int) int {
    if a < b {
        return a
    }

    return b
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值