[JavaScript 刷题] DP - 组成整数的最小平方数数量, leetcode 279
Posted GoldenaArcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JavaScript 刷题] DP - 组成整数的最小平方数数量, leetcode 279相关的知识,希望对你有一定的参考价值。
[javascript 刷题] DP - 组成整数的最小平方数数量, leetcode 279
上一篇 组成整数的最小平方数数量, leetcode 279 中使用了 BFS 的方式实现,这里使用 DP 完成。
其实这道题和 DP 地经典切段、选择硬币的套路还是一样的。
题目如下:
Given an integer
n
, return the least number of perfect square numbers that sum ton
.A perfect square is an integer that is the square of an integer; in other words, it is the product of some integer with itself. For example,
1
,4
,9
, and 16 are perfect squares while3
and11
are not.
解题思路
和常用的 DP 解决方案一样,这里也会需要一个容器去保存之前计算过的数值,毕竟递归的时间复杂度是
2
n
2^n
2n,将之前计算过的数值保存在容器中这一过程又称之为 memoization,也是 React 里面的 useMemo
的技巧。
这里有一个遍历是逃不掉的,就是完美平方数的遍历,以之前画的图为例:
每一层都需要对 1
, 4
, 9
进行迭代。
使用 memoization 的技巧就在于,当进行 degree = 3
的迭代是,degree = 2
的值会被保存在容器中,因此无需使用递归再一次进行计算。这也就是斐波那契数列在使用递归方法的复杂度为
O
(
2
n
)
O(2^n)
O(2n),但是使用 DP 的复杂度却只有
O
(
n
)
O(n)
O(n) 的原因。
具体实现方式如下:
-
新建一个长度为 n+1 的数组
这里直接初始化成
n+1
是因为数组是 0-based indexed,而且后面会需要用到 0 + k 2 0 + k^2 0+k2 获取完美平方数本身。后面做数值相加的时候,如 13 的组合包含 9 + 4 9 + 4 9+4,也就是 3 2 + 2 2 3^2 + 2^2 32+22,这样可以省去一步重复计算的步骤。
这里初始化的值可以用
n
,也可以取无穷大,差别不是很大。因为已知返回最大值是
n
自身——也就是n
个 1 2 1^2 12 相加,这些可以从一些边界值可以得出,如1
,2
,3
等。 -
从 index 1 开始计算
这里获取 1 的唯一方式是 0 + 1 2 0 + 1^2 0+12,在对比 n n n 与 0 + 1 2 0 + 1^2 0+12 后取较小值,也就是 1.
-
index = 2
这里开始会进入使用 memoization 的情况。2 的获取方式其实是这么来的:
a r r [ 1 ] + 1 2 arr[1] + 1^2 arr[1]+12
分别来源于 1 2 1^2 12 ——从完美平方数的循环中获取,加上获取
1
这个值所需的最小值。 -
index = 3
3 的获取方式同理:
a r r [ 2 ] + 1 2 arr[2] + 1^2 arr[2]+12
i < n i<n i<n 的值都已经被记录在了容器中,因此这里可以直接调取,并且加上完美平方数的值,获取最小值。
-
index = 4
从 4 之后开始就已经包含一些特殊值了,因为 4 的获取方式可以通过 2 2 2^2 22,这是一个完美平方数的值。
从 4 以后的数值会遇到两种情况:
- 通过完美平方数本身可以获取
- 通过组合完美平方数进行获取
在这种情况下就要进行判断,并且取最小值,这里的对比就是:
n n n 与 0 + 2 2 0 + 2^2 0+22 的对比,取最小值自然是 1 了。
-
index = 5
这里也是同样的方式进行操作,最后判断 a r r [ 2 ] + 1 2 arr[2] + 1^2 arr[2]+12 为最优解。
-
重复步骤。。。
遍历完整个数组的长度之后,整个数组都会被填充完成,因此直接返回 arr[n]
即可。
使用 JavaScript 解题
DP 的代码会比 BFS 的简单一些,需要注意的就是外层的 for
循环为 [1, 2, ..., n]
,第二层循环体的条件为 [1, ..., i]
。
第二层循环为了获取完美平方数,因此当完美平方数大于当前值的时候,就可以跳出这一层循环了。
nums[i] = Math.min(nums[i], 1 + nums[i - squareVal]);
是为了更新当前所能获取的最小值。
/**
* @param number n
* @return number
*/
var numSquares = function (n)
const nums = new Array(n + 1).fill(n);
nums[0] = 0;
for (let i = 1; i <= n; i++)
for (let j = 1; j < i + 1; j++)
const squareVal = j * j;
if (squareVal > i) break;
nums[i] = Math.min(nums[i], 1 + nums[i - squareVal]);
squareVal;
return nums[n];
;
console.log(numSquares(3));
console.log(numSquares(4));
console.log(numSquares(12));
console.log(numSquares(13));
开发者涨薪指南
48位大咖的思考法则、工作方式、逻辑体系
以上是关于[JavaScript 刷题] DP - 组成整数的最小平方数数量, leetcode 279的主要内容,如果未能解决你的问题,请参考以下文章
[JavaScript 刷题] DP - 买卖股票的最佳时机,leetcode 121