leetcode--279 完全平方数

 

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

示例 1:

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

示例 2:

输入: n = 13

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

解题思路:当没有仔细看题目时先想到了贪心算法,即13=1+1+1+1+9,但题目中要求最小平方数,所以考虑其他方法

BFS建模:考虑将问题转为图论问题处理,从n到0共n+1个节点,每个节点是一个数,如果两个节点Vi Vj相差一个完全

平方数,则连接Vi Vj为一条边,这样就得到了一个无权图,原问题转为求n到0的最短路径。利用下图说明的原理:

例如当输入n=5时,

1 在[0, n]范围内找到与n相差一个完全平方数的4和1,并记录节点出现的次数,即将(4,1)(1, 1)存入队列中,

2 从队列中弹出4,从4出发寻找与4相差一个完全平方数的3和0,并将(3, 2)(0, 2)存入队列;

3 从队列中弹出1,从1出发寻找与1相差一个完全平方数的0,并将(0, 2)存入队列

4 从队列中弹出3,从3出发寻找与3相差一个完全平方数的2,并将(2, 3)存入队列

5 从队列中弹出0,发现已经到0了,对应的路径为最短路径,即0节点对应的次数2

具体代码:

class Solution {
public:
    int numSquares(int n) {
        queue<pair<int, int>> q;
        q.push(make_pair(n, 0));
        while (q.size() != 0)
        {
            //q.push();
            pair<int, int> temp = q.front();
            q.pop();
            n = temp.first;
            int step = temp.second;

            if (n==0)
            {
                return step;
            }

            for (int i = 1; n-i*i>=0; i++)
            {
                q.push(make_pair(n-i*i, step+1)); // 从n到n-i*i走了step步
            }

        }

        return 0;
    }
};

改进:由于不同的路径会到达同一个节点,导致队列中记录了同一个节点的重复信息,导致上述的超时,而实际上求最短路径时每个节点只能出现一次,也就是说当发现一个节点已经出现在队列中时,就不再存储其相关信息,这样能够大幅降低时间消耗

class Solution {
public:
  int numSquares(int n)
    {
        queue<pair<int, int>> q;
        q.push(make_pair(n, 0));
        vector<bool> hasVisited(n+1, false);   //初始化为0
        hasVisited[n] = true;     //
      
        while (q.size() != 0)
        {
            n = q.front().first;
            int step = q.front().second;
            q.pop();

            if (n==0)
            {
                return step;
            }

            for (int i = 1; ; i++)
            {
                int tmp = n - i*i;

                if (tmp<0)
                {
                    break;
                }

                if (!hasVisited[tmp])            //访问过的节点不再访问
                {
                    q.push(make_pair(tmp, step + 1)); // 从n到n-i*i走了step步
                    hasVisited[tmp] = true;    //访问过的节点置为true
                }
            }

        }

        return 0;
    }

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值