Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
从一堆数1, 4, 9...中选取几个数使得和达到n,想到背包。由于是可以任取多次, 所以是完全背包. 让f[i][j]表示前i个元素能组成和为j的最短长度。这道题与之前的不同点一个在于是选取长度最短的,要用min,意味着有些数要初始化成MAX。还有一点也是比较tricky的点是状态转移方程是f[i][j - nums.get(i - 1)] ,而不是f[i - 1][j - nums.get(i - 1)] ,因为可以利用i来组成[j - nums.get(i-1)].
class Solution {
public int numSquares(int n) {
List<Integer> nums = new ArrayList<>();
for (int i = 1; i <= n; i++) {
double pow = Math.pow(i, 2);
if (pow > (double) n) {
break;
}
nums.add((int)pow);
}
int m = nums.size();
int[][] f = new int[m + 1][n + 1];
for (int j = 1; j <= n; j++) {
f[0][j] = Integer.MAX_VALUE;
}
for (int i = 0; i <= m; i++) {
f[i][0] = 0;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
f[i][j] = f[i - 1][j];
if (j - nums.get(i - 1) >= 0) {
f[i][j] = Math.min(f[i][j], f[i][j - nums.get(i - 1)] + 1);
}
//System.out.println(i + "," + j + ": " + f[i][j]);
}
}
return f[m][n];
}
}
时间复杂度为O(mn).
class Solution {
public int numSquares(int n) {
List<Integer> nums = new ArrayList<>();
for (int i = 1; i <= n; i++) {
double pow = Math.pow(i, 2);
if (pow > (double) n) {
break;
}
nums.add((int)pow);
}
int m = nums.size();
int[] f = new int[n + 1];
f[0] = 0;
for (int i = 1; i <= n; i++) {
f[i] = Integer.MAX_VALUE;
}
for (int i = 0; i < m; i++) {
for (int j = nums.get(i); j <= n; j++) {
if (f[j - nums.get(i)] != Integer.MAX_VALUE) {
f[j] = Math.min(f[j], f[j - nums.get(i)] + 1);
}
//System.out.println(i + "," + j + ": " + f[i][j]);
}
}
return f[n];
}
}