LeetCode:279 完全平方数 动态规划 / BFS

题目描述

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

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

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

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/perfect-squares
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

动态规划

一眼dp啊,将一个数分成两半,比如 n = n - j*j + j*j,问题转化为求 n - j*j 的完全平方数和最小个数,枚举所有 j 找最小,光速写了一个

状态转移 dp[i] = dp[i-j*j]+1

class Solution {
public:
    int numSquares(int n)
    {
        vector<int> dp(n+1, INT_MAX);  
        for(int i=0; i*i<=n; i++) dp[i*i]=1;
        if(dp[n]!=INT_MAX) return dp[n];
        for(int i=1; i<=n; i++)
        {
            if(dp[i]!=INT_MAX) continue;
            for(int j=1; j*j<=i; j++)
                dp[i] = min(dp[i], dp[i-j*j]+1);
        }
        return dp[n];
    }
};

但是考虑到题目的tag是bfs,面子还是要给一个的

bfs解法

比如当前节点是 n,遍历 j ,使得满足n-j*j >=0 那么 n-j*j 就是下一个节点,入队,重复操作直到遍历到 n=0,说明找到解了

注意:这里j从大数开始遍历,保证我们每次都能先尽可能的缩小问题的规模

代码(未优化,下面有优化版本)
在这里插入图片描述

class Solution {
public:
    int numSquares(int n)
    {
        int ans = 0;
        deque<int> q;
        q.push_back(n);
        while(!q.empty())
        {
            ans++;
            int qs = q.size();
            for(int i=0; i<qs; i++)
            {
                int tp=q.front(); q.pop_front();
                if(tp==0) return ans-1;
                for(int j=(int)sqrt(tp); j>=1; j--)
                    q.push_back(tp-j*j);
            }
        }
        return ans-1;
    }
};

剪枝
剪枝的思路就是如果之前遍历过的节点,之后就不再遍历它,比如 n到 n-4,有两条路,n-2是之前层就遍历过的,那么如果在更深的层又遍历到了,那么肯定不是最优解
在这里插入图片描述

代码(还是很慢是因为他们都是用四平方定理做的,常数时间),但是不论结果如何这种剪枝的思想在bfs种非常重要
在这里插入图片描述

class Solution {
public:
    int numSquares(int n)
    {
        int ans = 0;
        deque<int> q;
        q.push_back(n);
        vector<int> vis(n+1, false);
        while(!q.empty())
        {
            ans++;
            int qs = q.size();
            for(int i=0; i<qs; i++)
            {
                int tp=q.front(); q.pop_front();
                vis[tp]=true;
                if(tp==0) return ans-1;
                for(int j=(int)sqrt(tp); j>=1; j--)
                    if(!vis[tp-j*j]) q.push_back(tp-j*j);
            }
        }
        return ans-1;
    }
};
发布了199 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/104671382