题目

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

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

示例 1:

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

示例 2:

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

提示:

1 <= n <= 10^4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/perfect-squares
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

思路和322题零钱兑换基本是一样的。这个题的「平方数因子」对应322的硬币,这就要平方一下而已,都是求花费最少的数目。

通过这个题,体会到了完全背包问题交换内外两层循环的差异。

代码

n在内层 平方数因子在外层

一般会将实现目标(target)的方式(way)写在循环外层,目标写在内层。对于本题而言就是平方数因子写在外层,题目的n写在内层,就是下面的写法。

这种写法需要一开始进行初始化,尤其是求最小值时,需要将dp数组都赋一个极大值,一般dp[0]要单独考虑一下,如果使用了Arrays.fill(),一定记得再单独修改dp[0]。

  1. class Solution {
  2. public int numSquares(int n) {
  3. int[] dp = new int[n + 1];
  4. Arrays.fill(dp, n);
  5. dp[0] = 0;
  6. for (int i = 1; i * i <= n; i++) {
  7. for (int j = i * i; j <= n; j++) {
  8. dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
  9. }
  10. }
  11. return dp[n];
  12. }
  13. }

n在外层 平方数因子在内层

交换内外层循环的位置也是可以的,这种写法可以在循环内层将dp[i]赋一个极大值,且dp[0]是默认的0就正好。

但是,一般情况下,这种写法会和上面的写法慢一个常数级的时间,从循环变量的范围就可以看出来,不过差异不太明显。

  1. class Solution {
  2. public int numSquares(int n) {
  3. int[] dp = new int[n + 1];
  4. for (int i = 1; i <= n; i++) {
  5. dp[i] = n;
  6. for (int j = 1; j * j <= i; j++) {
  7. dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
  8. }
  9. }
  10. return dp[n];
  11. }
  12. }