# LC 279. Perfect Squares
### [Problem link](https://leetcode.com/problems/perfect-squares/)
###### tags: `leedcode` `python` `c++` `medium` `DP` `BFS`
Given an integer <code>n</code>, return the least number of perfect square numbers that sum to <code>n</code>.
A **perfect square** is an integer that is the square of an integer; in other words, it is the product of some integer with itself. For example, <code>1</code>, <code>4</code>, <code>9</code>, and <code>16</code> are perfect squares while <code>3</code> and <code>11</code> are not.
**Example 1:**
```
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
```
**Example 2:**
```
Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.
```
**Constraints:**
- <code>1 <= n <= 10<sup>4</sup></code>
## Solution 1 - DP
#### Python
```python=
class Solution:
def numSquares(self, n: int) -> int:
squares = [i**2 for i in range(1, int(math.sqrt(n)) + 1)]
dp = [float("inf")] * (n + 1)
dp[0] = 0
for square in squares:
for j in range(square, n + 1):
dp[j] = min(dp[j], dp[j - square] + 1)
return dp[-1]
```
#### C++
```cpp=
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 1, INT_MAX);
dp[0] = 0;
vector<int> nums;
for (int i = 1; i <= int(sqrt(n)); i++) {
nums.push_back(i * i);
}
for (int i = 0; i < nums.size(); i++) {
for (int j = nums[i]; j <= n; j++) {
if (dp[j - nums[i]] != INT_MAX) {
dp[j] = min(dp[j], dp[j - nums[i]] + 1);
}
}
}
return dp.back();
}
};
```
## Solution 2 - BFS
#### Python
```python=
class Solution:
def numSquares(self, n: int) -> int:
q = deque([(n, 0)])
squares = [i**2 for i in range(int(sqrt(n)) + 1)]
seen = set()
while q:
num, res = q.popleft()
if num == 0:
return res
for i in range(1, int(sqrt(num)) + 1):
candidate = num - squares[i]
if candidate < 0:
continue
if candidate not in seen:
q.append((candidate, res + 1))
seen.add(candidate)
```
>### Complexity
>| | Time Complexity | Space Complexity |
>| ----------- | ----------------- | ---------------- |
>| Solution 1 | O($\sqrt{n}$ * n) | O(n) |
>| Solution 2 | O($\sqrt{n}$ * n) | O($\sqrt{n}$) |
## Note
### sol1:
將平方數當成物品, n=背包容量, 這樣就成了無限背包的題目了.
跟[LC 322. Coin Change](https://hackmd.io/@Alone0506/HJXLBpgS3)一樣
c++:
不確定是否每個數都可以被perfect square組合, 如果會, 則可能會return INT_MAX,
如果不會, 則if (dp[j - nums[i]] != INT_MAX)這個判斷可以拿掉, 因為不會出現dp前面的數字為INT_MAX的情況.
### sol2:
res在每一輪的BFS中都會+1, 所以遇到num == 0直接return res就是最小值了.
sol2 time complexity: 每一輪會跑$\sqrt{num}$次, 最多跑n次, 且num <= n, 所以TC = $\sqrt{n}$ * n, 但sol2的時間複雜度較sol1小.