[LeetCode] 279. Perfect Squares(完全平方数)
-
Difficulty: Medium
-
Related Topics: Math, Dynamic Programming, Breadth-first Search
Description
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...
) which sum to n.
给定一个正整数 n,现需要用完全平方数(1
, 4
, 9
, 16
)的和凑出 n,问所需平方数的最小值。
Examples
Example 1
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
Example 2
Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.
Solution
先给出一个 naive 的做法,暴力搜索,大致基于下式进行计算(将题目所求的函数记为 \(f(n)\)):
\[f(n) = \begin{cases}
1& n 是完全平方数\\
\min(f(i) + f(n - i)) \; \{ i \in [1, n / 2] \} & else
\end{cases}
\]
为了防止重复计算,还是采用了记忆化搜索的方法,结果华丽丽的 TLE 了(input = 6175),而我本地跑这组测试数据的时候直接爆栈了……
import kotlin.math.floor
import kotlin.math.min
import kotlin.math.sqrt
class Solution {
private val memo = hashMapOf<Int, Int>()
fun numSquares(n: Int): Int {
if (memo.containsKey(n)) {
return memo.getValue(n)
}
if (n.isPerfectSquare()) {
memo[n] = 1
return 1
}
var result = Int.MAX_VALUE
for (i in 1..(n / 2)) {
result = min(result, numSquares(i) + numSquares(n - i))
}
memo[n] = result
return result
}
private fun Int.isPerfectSquare(): Boolean {
val root = floor(sqrt(this.toDouble())).toInt()
return root * root == this
}
}
自然只能找其它解法了,以下一个解法来自 discussion。考虑以下等式(还是一样,将原函数记为 \(f(n)\)):
\[f(0) = 0 \\
f(1) = f(0) + 1 = 1 \\
f(2) = f(1) + 1 = 2 \\
f(3) = f(2) + 1 = 3 \\
f(4) = \min(f(4 - 1 \times 1) + 1, f(4 - 2 \times 2) + 1) = \min(f(3) + 1, f(0) + 1) = 1 \\
f(5) = \min(f(5 - 1 \times 1) + 1, f(5 - 2 \times 2) + 1) = \min(f(4) + 1, f(1) + 1) = 2 \\
... \\
f(13) = \min(f(13 - 1 \times 1) + 1, f(13 - 2 \times 2) + 1, f(13 - 3 \times 3) + 1) = \min(f(12) + 1, f(9) + 1, f(4) + 1) = 2
\]
所以最后的状态转移方程是:
\[f(n) = \min(f(n - i \times i) + 1)(其中 n - i \times i \geq 0 且 i \geq 1)
\]
代码如下:
import kotlin.math.min
class Solution {
fun numSquares(n: Int): Int {
val dp = IntArray(n + 1) { Int.MAX_VALUE }
dp[0] = 0
for (i in 1..n) {
var min = Int.MAX_VALUE
var j = 1
while (i - j * j >= 0) {
min = min(min, dp[i - j * j] + 1)
j++
}
dp[i] = min
}
return dp.last()
}
}