279. 完全平方数

279. 完全平方数

leetcode 279. 完全平方数


题目:279. 完全平方数

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

示例1:

输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.

示例2:

输入: n = 13
输出: 2
解释: 13 = 4 + 9.

方法一:BFS(广度优先搜索)

思路:BFS(广度优先搜索),将小于等于n的所有平方数都视为可扩展搜索的方向,每次扩展将当前数减去该扩展方向的平方数即为扩展后的数。直至扩展到第一个为0的数时,搜索结束。

运行数据:执行用时:25 ms,内存消耗:39.5 MB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// LeetCode指定调用方法
public int numSquares(int n) {

// 记录结果
int result = 0;

// 记录可用平方数
List<Integer> squareNums = new ArrayList<Integer>();

// 求可用平方数
for (int i = 1; i * i <= n; i++) {
squareNums.add(i * i);
}

// 标记该数是否在BFS中扩展过
boolean[] marks = new boolean[n + 1];

// 用于BFS的队列
Queue<Integer> queue = new LinkedList<>();

// 将第一个数入队
queue.offer(n);

// 记录当前队列的长度,当队列为空时,BFS全部搜索结束(用以代替 queue.isEmpty() 增加每次循环判断时的效率)
int queneLen = 1;

// BFS
while (queneLen > 0) {

// 记录当前扩展轮的数的个数
int currentQueueLen = queneLen;

// 更新结果
result++;

// 扩展当前轮次的数
while (currentQueueLen-- > 0) {

// 将队列中第一个数出队
int currentNum = queue.poll();

// 更新当前队列长度
queneLen--;

// 遍历平方数,扩展收索
for (Integer squareNum : squareNums) {

// 记录扩展后的数
int nextNum = currentNum - squareNum;

// 如果扩展数不可用,后面的数也不可以用,此时直接退出循环(根据前面的生成平方数的规则,后面的平方数会越来越大,扩展数则会越来越小)
if (nextNum < 0) {
break;
}

// 如果扩展数为0,则BFS结束,返回结果
if (nextNum == 0) {
return result;
}

// 如果该数已被扩展过,则跳过该数
if (marks[nextNum]) {
continue;
}

// 将扩展数入队
queue.offer(nextNum);

// 标记该扩展数已被扩展
marks[nextNum] = true;

// 更新当前队列长度
queneLen++;
}
}
}

return 0;
}

方法二:动态规划(完全背包)

思路:动态规划(完全背包),将小于等于n的所有平方数都视为不同种类物品的空间,将所求的数视为背包容量,将整个问题转换成求用最少的物品完全装满背包 ,不限制每种物品的数量,即转换为完全背包问题进行解决。

运行数据:执行用时:39 ms,内存消耗:38.9 MB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// LeetCode指定调用方法
public int numSquares(int n) {

// 记录可用平方数
List<Integer> squareNums = new ArrayList<Integer>();

// 求可用平方数
for (int i = 1; i * i <= n; i++) {
squareNums.add(i * i);
}

// 动态规划记录数组,f[j]表示装满背包空间为j的最小物品数
int[] f = new int[n + 1];

// 初始化 动态规划记录数组
Arrays.fill(f, Integer.MAX_VALUE);
f[0] = 0;

// 动态规划
for (Integer squareNum : squareNums) {
for (int j = squareNum; j <= n; j++) {

// 状态转移方程
f[j] = Math.min(f[j], f[j - squareNum] + 1);
}
}

return f[n];
}

学习所得,资料、图片部分来源于网络,如有侵权,请联系本人删除。

才疏学浅,若有错误或不当之处,可批评指正,还请见谅!


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×