LeetCode #279 Perfect Squares
Question
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.
方法一:动态规划
time complexity:O(n^2)
很容易想到动态规划的方法,先求出1, 2, 3, ..., n-1的最小平方数个数值,再求出n的最小平方数个数值。动态转移方程为:
f(i) = min([ f[k]+f[i-k] for k in range(1, i)] )
class Solution: def numSquares(self, n: int) -> int: import math f = [0] f.append(1) for i in range(2, n+1): if i == int((math.sqrt(i))) ** 2: f.append(1) else: f.append(min([f[k]+f[i-k] for k in range(1, i)])) return f[n]
TLE,时间复杂度太高,502 / 588 test cases passed.
方法二:动态规划,开方剪枝
time complexity:O(n*sqrt(n))
方法一的大体思路不错,但由于枚举了1, 2, 3, ..., i-1所有的值,导致此步用了O(n),但其实没必要枚举1, 2, 3, ..., i-1之间配对的值,只需要枚举完全平方数就行了,所以可以改进为只对完全平方数进行枚举。
class Solution: def numSquares(self, n: int) -> int: f = [n] * (n+1) f[0] = 0 f[1] = 1 for i in range(2, n+1): j = 1 while j*j <= i: f[i] = min(f[i], f[i-j*j]+1) j+=1 return f[-1]
目测还是会超时
方法三:BFS
time complexity:O(sqrt(n) ^ k) (k平均情况不确定,由方法四可知,最坏情况是4)
以13为例:
class Solution: def numSquares(self, n: int) -> int: record = [(n,0)] for num, level in record: if num == 0: return level i = 1 while i*i <= num: record.append((num-i*i, level+1)) i += 1
用此最简单直接的BFS, 相当于把所有可能全部存在record里了,没有及时清理没有用的内存,此题导致MLE(Memory Limit Exceeded)了
1 class Solution: 2 def numSquares(self, n: int) -> int: 3 import math 4 5 level = 0 6 front, end = set([n]), set([0]) 7 while front: 8 if front & end: return level 9 front = set([num-i*i for num in front for i in range(1, int(math.sqrt(num))+1)]) 10 level += 1
此方法为上面BFS的改进,level只需要用一个变量存,因为BFS中level递增。值得一提的是front和end,即搜索的当前状态和终止状态,一旦两种有交集,代表当前到了终止状态,其采用了set而不用list,可以减少重复情况带来的重复计算。
从语言技巧的角度,可以注意第9行front更新语句的写法,简洁、方便、易读。
方法四:四平方和定理
time complexity:
参考: