LeetCode279. 完全平方数

  首先不能使用贪心算法,以12为例,如果用贪心则为 12 = 9 + 1 + 1 + 1, 与实际情况12 = 4 + 4 + 4不符。

☆☆☆☆思路1: BFS。

  一层一层的算,第一层依次减去一个平方数得到第二层,第二层依次减去一个平方数得到第三层。直到某一层出现了 0,此时的层数就是我们要找到平方数和的最小个数。         

  如下图,灰色表示当前层重复的节点,不需要处理。此时是第 3 层(从 0 计数),所以答案是3.

注:visited应该可以用一个数组记录(visited[n]),表示当前数字是否曾经入队,如果入过队了则不用再入队,因为这条路径长度必定大于等于之前入队的那条路径长度(在同一层是等于,在上一层是大于),图中漏标几个数字。

☆☆☆☆思路2:动态规划。与零钱兑换问题类似,见【40讲系列13】动态规划

class Solution {
    public int numSquares(int n) {
        /**
         * 方法1: 动态规划
         *      dp[i]:表示完全平方数和为 i 的 最小个数
         */
        /*
        int[] dp = new int[n + 1];
        dp[0] = 0;
        for (int i = 1; i <= n; i++) {
            dp[i] = i; // 最差的情况下,全由1相加得到
            //依次减去一个平方数
            for (int j = 1; i - j*j >= 0; j++) { // 注意i - j*j可以取到0
                dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
            }
        }
        return dp[n];
        */
        /**
         * 方法2: BFS
         */
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(n);
        boolean[] visited = new boolean[n + 1];
        visited[n] = true;
        int level = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            level ++;
            for (int i = 0; i < size; i++) {
                int cur = queue.poll();
                //依次减 1, 4, 9... 生成下一层的节点
                for (int j = 1; j * j <= cur; j++) {
                    int temp = cur - j*j;
                    if (temp == 0) {
                        return level;
                    }
                    if (!visited[temp]) {
                        queue.offer(temp);
                        visited[temp] = true;
                    }
                }
            }
        }
        return 0;
    }
}
原文地址:https://www.cnblogs.com/HuangYJ/p/14161649.html