LeetCode 279.完全平方数

264 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目:给定一个整数,返回和是这个整数的完全平方数的最少数量。

完全平方数是指:当一个数等于另一个数的平方时,这个数就是完全平方数,例如1、4、9、16、25等等都是完全平方数。

例如:输入n=12,则因为4=2*2,而12=4+4+4,因此输出为3。

解题思路

额,没有思路。。。解答一下官方题解的思路吧。

首先如果给定的整数其本身就是完全平方数,那直接返回1了。如果不是的话,例如12,我们知道在12之前的完全平方数有149,可系统可不知道,我们怎么得到这个结果?其实很简单,因为(12)\sqrt(12)的值在3-4这个范围,且必然小于4,因此其之前的完全平方数就是123的平方。得到了完全平方数,我们还需要将给定的数按照完全平方数进行组合,如12我们可以得到以下组合:

  1. 1 + 1 + 1 + 9
  2. 4 + 4 + 4

第一种组合要四个,第二种组合要三个,很明显第二种。

完全平方数可能较为抽象不好理解,我们将本题具体化一下:

某个人想买一个价值为n的东西,现在有金币分别为1、4、9、16....问至少需要花几枚硬币才可以买到东西?

我们首先假设价值为n的东西至少要花f(n)f(n)个金币,我们枚举前面所有可能的金币的范围为1---(n)\sqrt(n),假设范围是1---j,那么f(n)=f(njj)+f(jj)f(n) = f(n-j*j) + f(j*j) ,此公式即为动态规划的转移方程,此处必须保证两个括号内的要等于n,这一点比较重要,也是理解本题的关键。而我们知道j*j必然是有一枚金币可以对应的,因此f(jj)=1f(j*j)=1,可得如下代码:

public int numSquares(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 0;
    for(int i=1;i<=n;i++){
        dp[i] = i;
        for(int j=1;i-j*j>=0;j++){
            dp[i] = Math.min(dp[i], dp[i-j*j]+dp[j*j]);
        }
    }
    return dp[n];
}

时间复杂度和空间复杂度都是O(n)O(n)