Description
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, …) which sum to n.
Example 1:
Input:
n = 12
Output:
3
Explanation:
12 = 4 + 4 + 4.
Example 2:
Input:
n = 13
Output:
2
Explanation:
13 = 4 + 9.
分析
题目的意思是:把一个数分为几个数的平方和。
- 这道题目用了四数平方和定理,当然另一种解法是动态规划,这里介绍四数平方和定理,任意一个正整数均可表示为4个正整数的平方和,即结果只有1,2,3,4中的一个;然后可以化简,如果一个数里面含有因子4,可以除掉,不影响结果,自己验证;如果一个数除以8余7,则这个数肯定由四个数平方和组成,证明略;接下来我们就只需要判断是1,2,3个整数的平方和了。判断1个和2个整数的平方和很好判断,如代码,如果都不是那就是3个啦,如最后一行代码。
C++代码
class Solution {
public:
int numSquares(int n) {
while(n%4==0) n=n/4;
if(n%8==7) return 4;
for(int a=0;a*a<n;a++){
int b=sqrt(n-a*a);
if(a*a+b*b==n){
return !!a+!!b;
}
}
return 3;
}
};
Python
如果预先把所有可能值得平方求出来,这道题就变成了一个经典的dp问题了,然后就可以套用递推公式:
dp[i][j]=min(dp[i-1][j],dp[i][j-nums[i-1]]+1)
class Solution:
def numSquares(self, n: int) -> int:
# dp[i][j]=min(dp[i-1][j],dp[i][j-nums[i-1]]+1)
squares = []
i=1
while(i*i<=n):
squares.append(i*i)
i+=1
m = len(squares)
dp = [[n]*(n+1) for i in range(m+1)]
dp[0][0]=0
for i in range(1,m+1):
dp[i][0]=0
for j in range(n+1):
if j-squares[i-1]>=0:
dp[i][j]=min(dp[i-1][j],dp[i][j-squares[i-1]]+1)
else:
dp[i][j]=dp[i-1][j]
return dp[m][n]
下面的解法比较简洁,但不易想到:
class Solution:
def numSquares(self, n: int) -> int:
dp = [0]*(n+1)
dp[1]=1
for i in range(2,n+1):
j = 1
dp[i]=i
while j*j<=i:
dp[i]=min(dp[i],dp[i-j*j]+1)
j+=1
return dp[n]
参考文献
[LeetCode] Perfect Squares 完全平方数
Summary of 4 different solutions (BFS, DP, static DP and mathematics)