题目:
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
.
题意:
给定一个正整数n,求相加等于n的完全平方数(例如 1, 4, 9, 16, ...)的最小个数。
转载:https://leetcode.com/discuss/58056/summary-of-different-solutions-bfs-static-and-mathematics
思路:动态规划
如果一个数x可以表示为一个任意数a加上一个平方数bxb,也就是x=a+bxb,那么能组成这个数x最少的平方数个数,就是能组成a最少的平方数个数加上1(因为b*b已经是平方数了)。
初始化将dp数组置为无穷大;令dp[y * y] = 1,其中:y * y <= n
状态转移方程:dp[x + y * y] = min(dp[x + y * y], dp[x] + 1)
其中:dp [i] 表示凑成i所需的平方和数字的最小个数,并且 x + y * y <= n
代码:C++版:440ms
class Solution { public: int numSquares(int n) { if(n<=0) return 0; //初始化将数组置为最大 vector<int> cntPerfectSquares(n+1, INT_MAX); cntPerfectSquares[0] = 0; for(int i=1; i<=n; i++){ for(int j=1; j*j<=i; j++){ cntPerfectSquares[i] = min(cntPerfectSquares[i], cntPerfectSquares[i-j*j] + 1); } } return cntPerfectSquares.back(); } };代码:72ms
public class Solution { public int numSquares(int n) { int[] dp = new int[n+1]; // 将所有非平方数的结果置最大,保证之后比较的时候不被选中 Arrays.fill(dp, Integer.MAX_VALUE); // 将所有平方数的结果置1 for(int i = 0; i * i <= n; i++){ dp[i * i] = 1; } // 从小到大找任意数a for(int a = 0; a <= n; a++){ // 从小到大找平方数bxb for(int b = 0; a + b * b <= n; b++){ // 因为a+b*b可能本身就是平方数,所以我们要取两个中较小的 dp[a + b * b] = Math.min(dp[a] + 1, dp[a + b * b]); } } return dp[n]; } }
静态动态规划;
代码:16ms
class Solution { public: int numSquares(int n) { if(n<=0) return 0; static vector<int> cntPerfectSquares({0}); while(cntPerfectSquares.size()<=n){ int m = cntPerfectSquares.size(); int cntSquares = INT_MAX; for(int i=1; i*i<=m; i++){ cntSquares = min(cntSquares, cntPerfectSquares[m-i*i] + 1); } cntPerfectSquares.push_back(cntSquares); } return cntPerfectSquares[n]; } };
基于数论。
代码:7ms
class Solution { public: int numSquares(int n) { if(is_square(n)) return 1; while((n & 3) == 0) n >>= 2; //等效于n%4 == 0 if((n & 7) == 7) return 4; //等效于 n%8 == 7 int sqrt_n = (int)(sqrt(n)); for(int i=1; i<=sqrt_n; i++){ if(is_square(n-i*i)){ return 2; } } return 3; } private: int is_square(int n){ int sqrt_n = (int)(sqrt(n)); return (sqrt_n*sqrt_n == n); } };
广度优先搜索算法实现。
代码:80ms
class Solution { public: int numSquares(int n) { if(n<=0) return 0; vector<int> perfectSquares; vector<int> cntPerfectSquares(n); for(int i=1; i*i<=n; i++){ perfectSquares.push_back(i*i); cntPerfectSquares[i*i-1] = 1; } if(perfectSquares.back() == n) return 1; queue<int> searchQ; for(auto& i : perfectSquares) searchQ.push(i); int currCntPerfectSquares = 1; while(!searchQ.empty()){ currCntPerfectSquares++; int searchQSize = searchQ.size(); for(int i=0; i<searchQSize; i++){ int tmp = searchQ.front(); for(auto& j : perfectSquares){ if(tmp + j == n){ return currCntPerfectSquares; }else if((tmp + j < n) && (cntPerfectSquares[tmp + j - 1] == 0)){ cntPerfectSquares[tmp + j - 1] = currCntPerfectSquares; searchQ.push(tmp + j); }else if(tmp + j > n){ break; } } searchQ.pop(); } } return 0; } };