leetcode-----279:完全平方数[1]

问题描述:https://leetcode-cn.com/problems/perfect-squares/description/

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

示例 1:

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

解法1:数论知识:

定理1:Lagrange 四平方定理: 任何一个正整数都可以表示成不超过四个整数的平方之和。

         可以参考:https://blog.csdn.net/wenzhong003/article/details/49930361?fps=1&locationNum=4

          那么这里只让输出这个组成的个数,所以必定是1 2 3 4中的一个,

         1.若是1,直接判断是不是平方数即可;

         2.对于4,还有定理  

             满足四数平方和定理的数n(这里要满足由四个数构成,小于四个不行),必定满足 n= 4^a(8b + 7)

             因此,满足这种格式,必然是4。

         3.对于2,可以采用穷举法:若n=a^2+b^2; 那么有2x=(a+b)^2+(a-b)^2; a,b都不超过sqrt(n);

        4.上述都不是,那么就返回3了。

class Solution {
    public:
        int numSquares(int n) {
            //1???
            double s=sqrt(n);
            int a=(int)(s);
            if(a*a==n)
                return 1;
            //2???
            for(int i=1; i<a+1; i++)
            {
                for(int j=1; j<a+1; j++)
                {
                    if(i*i+j*j==n)
                        return 2;
                }
            }
            //4???
            int nn=n;
            while(nn%4==0)
            {
                nn=nn>>2;
            }
            if((nn-7)%8==0)
                return 4;

            //3
            return 3;
        }
};

效率非常高,4ms。

方法2

通过动态规划方法:

其中dp[i]表示正整数i最少能由多个完全平方数组成,
一个正整数i,最多由i个1组成,所以将其初始化:dp[i] = i;
从1开始遍历i:对每一个平方数进行判断,如果i小于平方数,结束;如果i大于平方数,那么可能会出现更小的值:i-num值对应的最小个数加上(本身num)这1个平方数。

class Solution {
    public:
        int numSquares(int n) {

            int *dp=new int[n+2];
            int *ss=new int[n+2], scount=1;
            int s=1;
            int s1=0;
            int s2=s*s;
            for(int i=1; i<n+1; i++)
            {
                dp[i]=i;
                if(i==s2)
                {
                    dp[i]=1;
                    s1=s2;
                    s++;
                    s2=s*s;
                    ss[scount]=s1;
                    scount++;
                } else if(i<s2)
                {
                    for(int j=scount-1; j>1; j--)
                    {

                        dp[i]=min(dp[i],dp[ss[j]]+dp[i-ss[j]]);
                    }
                }
                cout<<dp[i]<<endl;
            }
            return dp[n];
        }
};


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值