DP solution
class Solution:
def numSquares(self, n: int) -> int:
""" tc O(NlnN) sc O(N)
"""
# dp[i]: given number is i, the least number of perfect squares that sum to i
dp = [n]*(n+1)
dp[0] = 0
for x in range(1,n+1):
i = 1
for i in range(1,int(sqrt(x))+1):
dp[x] = min(dp[x],dp[x-i**2]+1) #use while loop will cause TLE
return dp[-1]
BFS solution
class Solution:
def numSquares(self, n: int) -> int:
""" tc O(N^h/2) sc O(sqrt(N)**h) h: wirst case sqrt(N), sc means for a N-ary tree, max # can appear in level h
BFS solution
main idea: consider a graph consisting of 0,... n as its node, node u is connected with node v via an edge if on only if u = v + i**2
1. create queue, seen set, set offset 0, initialize its level as 0
2. each round of q, loop through possible perfect squares i**2, add it with node in q => v = u + i^2
3. there are 3 cases: (1) v == n (2) v > n: (3) v < n ; for case (1), shows we find the minimun level, so we can return directly; case (2) shows there is no case v can equal to n since v will keep increasing; for (3), there is still potential can be summed up to n so we push unseen v in the queue and mark the value to prevent repeated operation
"""
q = collections.deque()
q.append(0)
seen = set()
seen.add(0)
level = 0
while q:
size = len(q)
level += 1
for _ in range(size):
u = q.popleft()
for i in range(1,int(sqrt(n))+1):
v = u + i**2
if v == n:
return level
if v > n: # early termination
break
if v not in seen:
seen.add(v)
q.append(v)
return level
Math solution
class Solution:
def numSquares(self, n: int) -> int:
""" tc O(sqrtN) sc O(1)
main idea: based on lagrange's four square theorm, any num = 4^k*(8m+7)
"""
def is_sq(v):
rt = int(sqrt(v))
return rt**2 == v
if is_sq(n):
return 1
# 2
for i in range(1,int(sqrt(n)+1)):
v = n - i**2
if v < 0:
break
if is_sq(v):
return 2
# 4
while n%4 == 0 #n &3 == 0:
n >>= 2
if n%8 == 7 #n&7 == 7
return 4
return 3