题目
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...
)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
方案一(BFS)
**
import functools
import collections
class Solution:
def numSquares(self, n: int) -> int:
deque = collections.deque([n])
res = 0
while deque:
length = len(deque)
res += 1
for _ in range(length):
num = deque.popleft()
for square_num in self.getSquareNumList(num):
t = num - square_num
if t == 0:
return res
deque.append(t)
return -1
@functools.lru_cache(maxsize=None)
def getSquareNumList(self, n: int):
'''获取小于等于n的完全平方数列表'''
square_nums = []
i = 1
while i * i <= n:
square_nums.append(i * i)
i += 1
return square_nums
方案二(数学定理)
Lagrange 四平方定理: 任何一个正整数都可以表示成不超过四个整数的平方之和。
满足四数平方和定理的数n(这里要满足由四个数构成,小于四个不行),必定满足
class Solution:
def numSquares(self, n: int) -> int:
if n < 4:
return n
# 4^k * (8a + 7)
while n % 4 == 0:
n /= 4
if n % 8 == 7:
return 4
a = 0
while a ** 2 <= n:
b = int((n - a ** 2) ** 0.5)
if a ** 2 + b ** 2 == n:
return bool(a) + bool(b)
a += 1
return 3
方案三(动态规划)
import functools
class Solution:
def numSquares(self, n: int) -> int:
# 递推公式
# dp[i] = min(dp[i], dp[i − j] + 1)
dp = [i for i in range(n + 1)] # 初始化dp
for i in range(2, n + 1):
for j in self.getSquareNumList(i):
dp[i] = min(dp[i], dp[i - j] + 1)
return dp[-1]
@functools.lru_cache(maxsize=None)
def getSquareNumList(self, n: int):
'''获取小于等于n的完全平方数列表'''
square_nums = []
i = 1
while i * i <= n:
square_nums.append(i * i)
i += 1
return square_nums
原文
https://leetcode-cn.com/explore/learn/card/queue-stack/217/queue-and-bfs/874/
https://leetcode-cn.com/problems/perfect-squares/solution/dong-tai-gui-hua-bfs-zhu-xing-jie-shi-python3-by-2/