leetcode-279. Perfect Squares
来源:互联网 发布:设计师必备软件 编辑:程序博客网 时间:2024/06/07 08:31
leetcode-279. Perfect Squares
问题描述如下:
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, …) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
该问题要求求出能组成一个整数的最小的平方数是多少,即12=4+4+4,那么它的最小的平方数为3. 13=4+9,那么它的最小的平方数为2.
该问题有以下四种解法:(4种解法均来自https://discuss.leetcode.com/topic/24255/summary-of-4-different-solutions-bfs-dp-static-dp-and-mathematics)
解法一:数学解法
主要运用的是拉格朗日4平方数定理:
即任何一个自然数都可以由不超过4个的平方数组成:
该定理的维基百科和证明如下:
https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem
https://www.alpertron.com.ar/4SQUARES.HTM
于是,该完美平方数的证明可以转化为分别是否由1个,2个,3个,4个平方数组成的。
然后根据拉格朗日定理可知,只要一个数i满足
i=4
k,m均为>=0的整数,说明i最小由4个平方数组成
如果一个数是平方数,则说明一个数由一个平方数组成
判断一个数是否由两个组成,先减去i的最大平方数,再判断剩下的数是否是平方数。
最终代码如下:
class Solution {private: int is_square(int n) { int SqNum=(int)(sqrt(n)); return (SqNum*SqNum==n); }public: //根据拉格兰日的定理,每个整数都可以由4个平方数组成 int numSquares(int n) { //是否能由一个数字组成 if(is_square(n)) { return 1; } //是否能由三个数字组成 //根据拉格兰日定理可知 //只要n=4^(k*(8*m-7)) //先判断是否能被4整除 while((n&3)==0) //n%4==0 { n>>=2; } if((n&7)==7) //m%8==7 { return 4; } //判断是否能由两个数字组成 int sqrt_n=(int)(sqrt(n)); for(int i=1;i<=sqrt_n;++i) { if(is_square(n-i*i)) { return 2; } } return 3; }};
解法二:动态规划
直接说明递推公式吧,递推公式如下
result[0]=0;result[n]=min(result[n],result[n-j*j]+1);
每个一个数都可以由一个数加上一个平方数构成,由此关系可以构成一个递推公式
代码如下:
class Solution {public: int numSquares(int n) { if(n<=0) return 0; vector<int> result(n+1,10000); result[0]=0; for(int i=1;i<n+1;++i) { for(int j=1;j*j<=i;++j) { result[i]=min(result[i],result[i-j*j]+1); } } return result[n]; }};
解法三:静态动态规划
即通过创建static vector,OJ的多次函数调用来对一个动态规划的表做到多次利用,即numSquares(100)其实只要调用numSquares(10)的表就好,不需要创建新的表,相当于利用了OJ的小trick。
代码如下:
class Solution {public: int numSquares(int n) { if(n<=0) return 0; static vector<int> result({0}); while(result.size()<=n) { int m=result.size(); int minResult=INT_MAX; for(int i=1;i*i<=m;++i) { minResult=min(minResult,result[m-i*i]+1); } result.push_back(minResult); } return result[n]; }};
解法四:广度优先搜索
把小于等于n的平方看成一个图的结点,那么节点与节点之间是否相连取决于是否满足SquareNumber+i=j,i为原数字,j为结果数字,SquareNumber表示为平方数,同时维护一个数组cntSquareNumber,表示该结点是由几个平方数组成,这样利用广度优先搜索该图的平方结点直到SquareNumber+i=n,返回最终的最小的平方数,得到结果
class Solution {public: int numSquares(int n) { vector<int> cntNumber; //说明数字由几个平方数组成的数组 vector<int> cntSquareNumber(n); for(int i=1;i*i<=n;++i) { cntNumber.push_back(i*i); cntSquareNumber[i*i-1]=1; } if(cntNumber.back()==n) { return 1; } queue<int> resultQ; for(auto& i:cntNumber) { resultQ.push(i); } int result=1; while(!resultQ.empty()) { result++; int size=resultQ.size(); for(int i=0;i<size;++i) { int temp=resultQ.front(); for(auto& j:cntNumber) { if(temp+j==n) { return result; } else if((temp+j<n) && (cntSquareNumber[temp+j-1]==0)) { cntSquareNumber[temp+j-1]=result; resultQ.push(temp+j); } else if(temp+j>n) { break; } } resultQ.pop(); } } return 0; }};
- [leetcode] 279. Perfect Squares
- 279. Perfect Squares LeetCode
- leetcode 279. Perfect Squares
- leetcode 279. Perfect Squares
- [LeetCode]279. Perfect Squares
- LeetCode-279.Perfect Squares
- LeetCode *** 279. Perfect Squares
- leetcode.279. Perfect Squares
- LeetCode 279. Perfect Squares
- [leetcode] 279. Perfect Squares
- Leetcode-279. Perfect Squares
- LeetCode 279. Perfect Squares
- Leetcode 279. Perfect Squares
- [LeetCode]279. Perfect Squares
- 【LeetCode】 279. Perfect Squares
- (LeetCode) 279. Perfect Squares
- LeetCode 279. Perfect Squares
- LeetCode#279. Perfect Squares
- 最小生成树
- Spark面试问题
- Package java.util.concurrent Description(介绍)
- JVM调优学习总结
- mysql数据库开发常见问题及优化
- leetcode-279. Perfect Squares
- 剑指offer2 问题12 矩阵中的路径 Java实现
- 剑指Offer—32—把数组排成最小的数
- 分割矩阵---二分法
- 服务器地址更换后在cmd窗口通过命令行语句修改IDEA中git地址
- 新oschina的研究计划
- Android之getSystemService
- hdu 6181 Two Paths(次短路)
- 士兵杀敌(二)