「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题意描述
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
输入:n = 12 输出:3 解释:12 = 4 + 4 + 4
解法1:动态规划(DP)
分析:我们可能会去考虑一个数的最短平方和会不会和它之前的数的最短平方和有关联呢?想着想着就去尝试一下,以18为例子。
- 18的最短平方和可能=18-1^2的最短平方和的长度+1
- 16的最短平方和也是一样的思路
- =18-2^2的最短平方和的长度+1
- 14的最短平方和也是一样的思路
- =18-3^2的最短平方和的长度+1
- 9的最短平方和也是一样的思路
- =18-4^2的最短平方和的长度+1
- 10的最短平方和也是一样的思路
很容易的我们可以推导出我们的状态方程dp[i]=min(dp[i], dp[i-j^2]+1) && i>=j^2,有了状态方程,写代码也就比较轻松了。
var numSquares = function(n) {
let dp=new Array(n+1).fill(0)
for(let i=0;i<=n;i++){
dp[i]=i;
for(let j=0;i-j*j>0;j++){
dp[i]=Math.min(dp[i],dp[i-j*j]+1)
}
}
return dp[n]
};
解法2:递归+记忆化
思路:通过一个数组来保存曾经计算过的量,下一次使用时,直接用就不用再去计算,也就是我们说的记忆化数组。
var numSquares = function(n) {
let memo = [];
const getCount = (num) => {
if (num <= 3) {
return num;
}
// 若已计算过,直接返回
if (memo[num]) {
return memo[num];
}
let sqrt = Math.floor(Math.sqrt(num));
for (let i = sqrt; i >= 2; i--) {
let c = getCount(num - i * i);
// memo 记录 num 的最少的组合数个数
memo[num] = Math.min(memo[num] || Number.MAX_VALUE, c + 1);
}
return memo[num];
};
return getCount(n);
};
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤