再论力扣第279题--完全平方数

题目

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

示例1:

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

示例2

 

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

 

分析:

  之前曾做过一次这道题,当时是刚学了动态规划算法,然后正好拿这个题进行练习,通过定义一个状态转移数组,也顺利的解决了,但是经过力扣的测试,运行效率十分地的感人,运行时间长达上前毫秒,可见用动态规划算法实现的程序的性能并不怎么好。正好最近在温习了广度优先算法,那么这个题也正好可以通过BFS解决,所以就再研究一下咯。并且没想到,虽然程序写的更为复杂了,但是运行时间大大的缩减了,甚至优于百分之九十以上的人的程序。好吧,废话不多说,开始进行正式的分析。

  我们知道,任何一个正整数都可以由若干个完全平方数相加而得到,最简单的就是数值是几,就由多少个1相加,这是组成和的完全平方数最为多的情况。而题目中要求的是最少的情况,其实可以抽象为求最短路径。也就是说,将n设置为起点,目的地是0,而n每一次向0靠近的时候,可以向前走的距离是1~n之间的所有平方数,比如:

  n = 13   目的地:0 ,设置一个计数值用于记录遍历的层数,到达0时的计数值就是最终的结果;

  从13出发,作为BFS遍历的第一层,那么此时向0靠近时,可以走的距离分别由1、4、9,那么我们就都走一下试试;

  分别按照这三个距离向前走,到达的点分别是12、9、4,此时这三个点算作BFS遍历的第二层;

  开启遍历第二层,计数值加1,获取第二层的结点个数,分别向0靠近遍历,可走的距离依旧是小于等于各自顶点值的所有平方数,遍历完当前层的所有顶点之后,就得到了下一层的所有顶点;

  继续重复上述工作,到达目的地0时,就立马返回计数值。

  注意必须遍历完一层的顶点之后才能开始下一层,开启一层计数值就+1

代码:

public int numSquares(int n) {

        if ((int)Math.sqrt(n) * (int)Math.sqrt(n) == n){
            return 1;
        }
        List<Integer> squares = generateSquare(n);

        LinkedList<Integer> queue = new LinkedList<>();
        boolean[] isVisited = new boolean[n + 1];

        isVisited[n] = true;
        queue.offer(n);
        int count = 0;
        while (!queue.isEmpty()){
            int unum = queue.size();
            count++;

            while (unum-- > 0){
                Integer u = queue.poll();
                for (Integer square : squares) {

                    int next = u - square;

                    if (next == 0){
                        return count;
                    }else if (next < 0){
                        break;
                    }else {
                        if (isVisited[next]){
                            continue;
                        }else {
                            isVisited[next] = true;
                            queue.offer(next);
                        }
                    }

                }
            }

        }
        return count;
    }

    private List<Integer> generateSquare(int n){

        ArrayList<Integer> res = new ArrayList<>();
        for (int i = 1; i*i <= n; i++) {
            res.add(i*i);
        }

        return res;
    }

 

posted @ 2020-06-16 23:18  有心有梦  阅读(174)  评论(0编辑  收藏  举报