「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战」。
每日刷题第43天 2021.02.10
279.完全平方数
- leetcode原题链接:leetcode-cn.com/problems/pe…
- 难度:中等
- 方法:bfs、动态规划、dfs
题目
- 给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
- 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例
- 示例1
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4
- 示例2
输入: n = 13
输出: 2
解释: 13 = 4 + 9
提示
1 <= n <= 104
解法
- 思路的转换:之前书写的dfs大部分都是使用全局变量的方式,在后期的做题过程中,发现全局变量对于剪枝等操作非常的不方便,因此学习了其他的dfs写法,主要是将当前获取的值作为函数的返回值返回。
有返回值的dfs
dfs边界返回的条件:当所有的平方数均减完,最终结果为0,则返回0return 0
纯纯的模拟dfs
- 首先,预处理:计算出比当前数
n小的所有完全平方数,并将其存储在数组template中。 - 封装一个
nearBy函数,用于找出距离当前数最近的完全平方数.(便于后期在dfs中直接调用使用) - 核心dfs函数:返回值需要返回当前
n的完全平方数的最少数量。- 返回条件(dfs一定要写一个返回的条件,否则将会一直递归下去,那么就一直往深处走,不会再往回走)
- 接下来,查找当前
n的最近的完全平方数,因为每次dfs查找下去的数,需要减去的完全平方数一定比当前的值小。 for循环,将当前n所有能够由完全平方数组成的方式全部遍历到,并将其所有的数量,取min最小值。- 举例:
n = 12,比是12小的完全平方数有:9、4、1 - 第一种情况:
12 -> 9 -> 1 -> 1 -> 1 - 第二种情况:
12 -> 4 -> 4 -> 44存在两种情况:4或者1 -> 1 -> 1 -> 1
- 第三种情况:
12 -> 1 -> 1 -> 1 -> 1 -> 1 -> 1 -> 1 -> 1 -> 1 -> 1 -> 1 - 将三种情况获得的长度取
min,就是和为当前的n的完全平方数的最少数量。
- 举例:
- 切记: 一定要返回每一层已经得到的最少数量。否则就会导致只有递归到返回条件才有数值,其他的均为
NaN,本质上就是没有返回值导致的错误。return num
剪枝操作
- 在每次返回当前层的最少数量之前,将数据存储下来,避免下次再递归到这里重复计算。
- 在每次进入
dfs函数的时候,添加判断条件当前的n是否已经维护过最少数量,如果存在,直接返回使用即可。
/**
* @param {number} n
* @return {number}
*/
var numSquares = function(n) {
// 打表,先将当前数小于的完全平方数存储起来
// 每次查找到当前数距离最近的完全平方数
// 找到即:返回长度
let template = [];
for(let i = 1;;i++) {
if(i * i > n) break;
if(i * i == n) return 1;
template[i] = i * i;
}
// console.log(template);
let nearBy = function near(m) {
for(let i = template.length - 1; i >= 1; i--) {
if(m >= template[i]) return i;
}
}
// console.log(template,nearBy(126));
// let num = 0;
let min = Infinity;
// let ans = 0;
let visited = new Map();
function dfs(nearN) {
if(visited.has(nearN)){
return visited.get(nearN);
}
// console.log('nearN: ',nearN);
if(nearN == 0){
//ans = num;
// if(num <= min){
// min = num;
// }
return 0;
}
let tempt = nearBy(nearN);
// 需要for循环执行BFS
let num = Infinity;
for(let i = tempt; i >= 1; i--) {
// num++;
// 当前递归出来的值
num = Math.min(dfs(nearN - template[i]) + 1,num);
// visited.set(nearN,Math.min(num,visited.get(nearN)));
// num--;
}
visited.set(nearN,num);
// console.log('num: ',num);
return num;
}
return dfs(n);
// return visited.get(n);
};