LeetCode 279. 完全平方数
https://leetcode-cn.com/problems/perfect-squares/
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
解法1:递归 + 记忆数组
对于一个正整数数 n,我们需要找出它的最少完全平方数的组合个数。
首先考虑 n <= 3 的情况,这种情况下,最小的完全平方数就只有 1,因此 n 的完全平方组合个数就是 n。
然后来看 n >= 4 的情况,能够组成这个数的最大完全平方数很容易想到,就是 n 的平方根取整后的值,即: s = Math.floor(Math.sqrt(n)) ,假设这个值是 n 的组成数的其中一个,那剩下我们再对 n - s 做同样考虑即可。
穷举所有情况, [2, s] (s 为 n 的平方根取整后的值),直到当前的 n 小于等于 3 时,返回 n。
使用图来表示就是:
不过对于一些比较大的数字,我们在计算过程其实是会有很多重复计算的(因为我们使用了穷举),也就是假设一个数字 n,它的根号取整值是 s,我们最开始枚举 s * s 是 n 的组合数之一,然后计算包含 s^2 的组合数个数时,我们遇到了数字 x1,x2,x3 之后计算得到了组合数个数,我们再回到开头,继续枚举 (s-1) * (s-1) 作为 n 的组合数之一,在这个计算过程中,我们遇到了数字 y1,y2,x2,x3 之后得到了结果。那么在这个过程中,我们的 x2,x3 就是重复计算的数。
因此我们完全可以使用一个记忆数组 memeo 来根据当前的数字 n 记录 n 能够得到的最少的组合数,这样,当我们第二次遇到 x2 的时候,就能够凭借记忆数组直接返回 memo[x2],减少了我们的计算。
JS 代码:
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);
};
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!