# 279. Perfect Squares
#### Difficulty: Medium
link: https://leetcode.com/problems/perfect-squares
### 1. DP
#### $O(n \sqrt n)$ runtime, $O(n)$ space
用`dp[i]`來代表`numSquares(i)`的解,n扣掉一個平方數後,找出前面i用最少平方數的解。
Note: 實作上,盡量避免使用時間複雜度是 $O(log(n))$ 的`sqrt()`,用`j * j <= n`而不是`j <= sqrt(i)`。
##### C++
```C++=
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1, INT_MAX);
dp[0] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j * j <= i; ++j) {
dp[i] = min(dp[i], 1 + dp[i-j*j]);
}
}
return dp[n];
}
};
```
### 2. Math
#### $O(\sqrt n)$ runtime, $O(\sqrt n)$ space
#### a. Legendre's three-square theorem
Let $n$ be a natural number. $n=x^2 + y^2 + z^2$ is solvable in non-negative number
$\iff$ $n$ is not of the following form: $4^a(8b+7)$
#### b. Lagrange's four-square theorem
Every natural number can be represented as a sum of four non-negative integer squares.
根據以上兩個理論,正整數最多只會由4個平方數組成。只要不是$4^a(8b+7)$的形式,都可由<=3個平方數組成。
Note: 第5行`n /= 4`不影響平方數的個數,因為 $4=2^2$ 也是平方數。
##### C++
```C++=
class Solution {
public:
int numSquares(int n) {
//Use Lagrange's four-square theorem and Legendre's three-square theorem
while (n % 4 == 0) n /= 4;
if (n % 8 == 7) return 4;
unordered_set<int> square;
for (int i = 1; i * i <= n; ++i) {
square.insert(i * i);
}
if (square.count(n)) return 1;
for (int i = 1; i * i <= n; ++i) {
int j = n - i * i;
if (square.count(j)) return 2;
}
return 3;
}
};
```
###### tags: `leetcode`