279. 完全平方数

完全背包

import java.util.Arrays;

class Solution {
    public int numSquares(int n) {

        /**
         * dp[j]定义为和为j的完全平方数的最小个数
         * 因为是求最小值,因此所有位置初始化为最大值
         * 初始值dp[0] == 0
         */
        int[] dp = new int[n + 1];
        Arrays.fill(dp, n + 1);
        dp[0] = 0;

        /**
         * 完全背包
         * 本题求最小个数,因此无论是求组合还是排列都可以的
         * 外循环遍历物品(完全平方数的个数),内循环遍历背包容量(n)
         * 物品数最大为小于n的完全平方数的个数,即i * i <= n
         * i一定要从1开始,因为dp[j - i * i]中使用的是有实际意义的i,i不仅仅是索引
         */
        for (int i = 1; i * i <= n; i++) {

            for (int j = i * i; j <= n; j++) {
                dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
            }
        }

        return dp[n];
    }
}

/**
 * 时间复杂度 O(n*sqrt(n))
 * 空间复杂度 O(n)
 */

动态规划

class Solution {
    public int numSquares(int n) {

        /**
         * dp[i]定义为和为i的完全平方数的最少数量
         * dp[1] == 1
         */
        int[] dp = new int[n + 1];
        dp[1] = 1;

        /**
         * 如果i本身就是完全平方数,结果就是1
         * 否则,和为i的完全平方数最大不会超过Math.sqrt(i)向下取整
         */
        for (int i = 2; i <= n; i++) {

            dp[i] = Integer.MAX_VALUE;
            int max = (int) Math.sqrt(i);

            if (max * max == i){
                dp[i] = 1;
            }
            else {

                /**
                 * j的上界为max的平方
                 */
                for (int j = max * max; j >= 1; j--) {
                    dp[i] = Math.min(dp[i], dp[j] + dp[i - j]);
                }
            }
        }

        return dp[n];
    }
}

/**
 * 时间复杂度 O(n^2)
 * 空间复杂度 O(n)
 */

优化1——只遍历sqrt(n)次

class Solution {
    public int numSquares(int n) {

        int[] dp = new int[n + 1];
        dp[1] = 1;

        /**
         * 如果i本身就是完全平方数,结果就是1
         */
        for (int i = 2; i <= n; i++) {

            dp[i] = Integer.MAX_VALUE;
            int max = (int) Math.sqrt(i);

            if (max * max == i){
                dp[i] = 1;
            }
            else {

                /**
                 * 对于每个i的结果来说,构成平方的数都落在[1, sqrt(i)]中
                 * 因此j可以只遍历sqrt(i)次
                 * dp[i - j * j]表示减去j * j这个平方数以后的最小个数,因此最后结果dp[i]还要加上这一个
                 */
                for (int j = 1; j * j <= i; j++) {
                    dp[i] = Math.min(dp[i], dp[i - j * j]);
                }

                dp[i]++;
            }
        }

        return dp[n];
    }
}

/**
 * 时间复杂度 O(n*sqrt(n))
 * 空间复杂度 O(n)
 */

https://leetcode-cn.com/problems/perfect-squares/

posted @ 2022-01-20 16:42  振袖秋枫问红叶  阅读(54)  评论(0)    收藏  举报