LeetCode279—完全平方数(java版)

题目描述:

标签:广度优先搜索  数学  动态规划

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

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

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

代码:

《方法一:广度优先搜索》

 思路分析:

将从1~n的每个整数看成图中的一个节点,如果两个整数之差为一个平方数,那么这两个整数所在的节点就有一条边。求解最小的平方数数量,就是求解从节点n到节点0的最短路径。

1、定义一个方法,保存1~n之间的所有完全平方数。完全平方数1、4、9、16...可以看出两数之差为3,5,7,...,所以它们的差值也是成等差数列增长的。

2、定义一个队列,用于保存每层的节点;定义一个boolean数组v,保存节点是否被访问过。开始时加入n节点,并修改v[n]=true。

3、对队列中的每层元素遍历,求出n的下一层节点(即与n之间相差完全平方数的节点),一直到减去一个平方数等于0为止,说明找到了最短路径。

class Solution {
    public int numSquares(int n) {
        List<Integer> squres = generateSquares(n);
        Queue<Integer> q = new LinkedList<>();
        boolean[] v = new boolean[n+1];
        q.add(n);
        v[n] = true;
        int level = 0;
        while(!q.isEmpty()){
            int size = q.size();
            level++;
            while(size-- > 0){
                int cur = q.poll();
                for(int s : squres){
                    int next = cur - s;
                    if(next < 0){
                        break;
                    }
                    if(next == 0){
                        return level;
                    }
                    if(v[next]){
                        continue;
                    }
                    v[next] = true;
                    q.add(next);
                }
            }
        }
        return n;
    }

    public List<Integer> generateSquares(int n){
        List<Integer> squres = new ArrayList<>();
        int squre = 1;
        int diff = 3;
        while(squre <= n){
            squres.add(squre);
            squre += diff;
            diff += 2;
        }
        return squres;
    }
}

《二、动态规划》

 思路分析:

1、确定dp数组以及下标的含义——这里dp[i]表示和为 i 的完全平方数的最少数量

2、确定递推公式,先找到从1~n中存在的所有完全平方数,在对完全平方数遍历,当当前完全平方数square>i时,退出遍历,否则需要更新最少数量,min = min(min, dp[i-square] +1),dp[i] = min

3、dp数组初始化,可以不初始化

4、确定遍历顺序,for循环遍历,i从1到n

5、举例推导dp数组

6、最后返回所有dp[i]的和  

class Solution {
    public int numSquares(int n) {
        List<Integer> squares = generateSquares(n);
        int[] dp = new int[n+1];
        for(int i = 1;i <= n;i++){
            int min = Integer.MAX_VALUE;
            for(int square : squares){
                if(square > i){
                    break;
                }
                min = Math.min(min, dp[i - square] + 1);
            }
            dp[i] = min;
        }
        return dp[n];
    }

    public List<Integer> generateSquares(int n){
        List<Integer> list = new ArrayList<>();
        int square = 1;
        int diff = 3;
        while(square <= n){
            list.add(square);
            square += diff;
            diff += 2;
        }
        return list;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值