题目来自力扣
与之前做的:抢劫银行、买卖股票、表示数字……这些动态dp有所不同。
先给出这题的题目:
给你一个整数 n
,返回 和为 n
的完全平方数的最少数量 。
以下是题目中的两个示例:
输入:n =12
输出:3 解释:12 = 4 + 4 + 4
输入:n =13
输出:2 解释:13 = 4 + 9
刚看到这道题的时候,就想到一个定理:四平方和定理
内容:每个正整数都可以表示为至多4个正整数的平方和。 如果把0包括进去,就正好可以表示为4个数的平方和。 (拉格朗日和欧拉分别在1770年和1773年作出最后的证明)
由此,最终结果大致就限制在4及以内.
我在这给出最暴力的方法之一,暴力嘛,带点dp规划很正常:
思路:创建一个n+1个元素的数组,存储小于n的所有情况的个数,类似于打表,然后遍历n减去一个平方数的可能结果,加上对应位置的结果,找到这些可能结果的最小值即可。
例如:n=4,那么创建的数组中就是
这里每一个数字前面的加一就是对dp的步数调整,也就是至少要多走一步,后面的加数就是4 - i^2得到的可能的得数对应的已知步数,取所有可能的最小值即可。
给出算法的实现:
int numSquares(int n)
{
int arr[n + 1]; // 创造一个一维数组,记录比输入数字小的所有的可能情况
arr[0] = 0; // 初始定义为 0
for (int i = 1; i <= n; i++)
{
int min = INT_MAX;
for (int j = 1; j * j <= i; j++)
{
// 动态规划往后每一格需要的最小的平方数的个数
min = fmin(min, arr[i - j * j]);
} // 比 n 小的每一个数字都有相应的个数唯一表示,往后其实就只是往前找表相加而已
arr[i] = min + 1; // 加一维护次数的变化
}
return arr[n];
}