动态规划+贪心+BFS 279. 完全平方数

44 篇文章 0 订阅
15 篇文章 0 订阅

279. 完全平方数

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

示例 1:

输入: n = 12
输出: 3 

解释: 12 = 4 + 4 + 4.
示例 2:

输入: n = 13
输出: 2

解释: 13 = 4 + 9.

动态规划
设置dp数组,对小于n的每个平方数设置dp=1;
从2开始遍历每个数,对每个数再枚举每种平方数的凑法;
最后返回dp[n]即为答案;

class Solution {
public:
    int numSquares(int n) {
        //用1,4,9,16……凑n
        dp.resize(n+1,INT_MAX);
        for(int i=1;i*i<=n;i++){
            dp[i*i]=1;
            //if(i*i==n) return 1;
        }
            
        for(int i=2;i<=n;i++){            //从1~i用数最少的那个+剩余的数
            for(int j=1;j*j<i;j++)
                dp[i]=min(dp[i],dp[j*j]+dp[i-j*j]);
        }
        return dp[n];
    }
private:
    vector<int> dp;
};

贪心算法
递归实现对最少次数的枚举;
(1)将小于等于n的平方数全部保存在map中;
(2)最少数从1开始,递归得到最少树——每次递归遍历map;
(3)递归终止条件——cnt==1时;

class Solution {
public:
    int numSquares(int n) {
        for(int i=1;i*i<=n;i++)
            map[i*i]=1;
        //保存所有小于n的平方
        int cnt=1;
        while(!istrue(n,cnt)) cnt++;
        return cnt;
    }
private:
    unordered_map<int,bool> map;
    bool istrue(int n,int cnt){
        if(cnt==1) return map.count(n);
        for(auto t:map)
            if(istrue(n-t.first,cnt-1)) return true;
        return false;
    }
};

BFS+贪心
从第一层开始找;
每次看前一层的数是否有与平方数相等的数,有则返回当前层数;
无则将上一层的数减去每一个比自己小的平方数,前往下一层;

class Solution {
public:
    int numSquares(int n) {
        int cnt=0;
        for(int i=1;i*i<=n;i++)
            cut.push_back(i*i);
        queue.insert(n);
        while(1){
            ++cnt;
            set<int> next_queue;
            for(int tmp:queue){
                for(auto c:cut)
                {
                    if(c==tmp) return cnt;
                    else if(tmp<c) break;
                    else next_queue.insert(tmp-c);
                }
            }
            queue=next_queue;
        }
    }
private:
    set<int> queue;
    vector<int> cut;
};

注意点:使用两个set,代替queue,可有效去重,加快速度;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值