前言:这个专栏主要讲述动态规划算法,所以下面题目主要也是这些算法做的
我讲述题目会把讲解部分分为3个部分:
1、题目解析
2、算法原理思路讲解
3、代码实现
完全平方数
题目链接:完全平方数
题目
给你一个整数 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
解法
算法原理与解析
我们这题使用动态规划,我们做这类题目可以分为以下五个步骤
- 状态显示
- 状态转移方程
- 初始化(防止填表时不越界)
- 填表顺序
- 返回值
这一道题目和零钱兑换题目非常的类似,于是我们可以将这一道题目转换一下,将他变成零钱兑换。根据题目意思可以根据 n,得出能用于拼凑的数字,例如 n = 12,那么就只能在 [1, 4, 9]里面选择。这样就变成了一道零钱兑换题目。
要是不知道零钱兑换题目,可以看一看LeetCode刷题--- 零钱兑换-CSDN博客
代码实现
int coinChange(vector<int>& coins, int amount)
{
const int INF = 0x3f3f3f3f;
int n = coins.size();
vector<int> dp(amount + 1, INF); // 建表
// 初始化
dp[0] = 0;
for (int i = 1; i <= n; i++)
for (int j = coins[i - 1]; j <= amount; j++)
dp[j] = min(dp[j], dp[j - coins[i - 1]] + 1);
return dp[amount] >= INF ? -1 : dp[amount];
}
int numSquares(int n)
{
vector<int> v;
for (int i = 1; i*i <= n; i++)
{
v.push_back(i * i);
}
return coinChange(v, n);
}
代码优化
int numSquares(int n)
{
vector<int> dp(n + 1);
dp[1] = 1; // 初始化
for(int i = 2; i <= n; i++) // 枚举每个数
{
dp[i] = 1 + dp[i - 1]; // ⾄少等于 1 + dp[i - 1]
for(int j = 2; j * j <= i; j++) // ⽤⼩于 i 的完全平⽅数划分区间
dp[i] = min(dp[i], dp[i - j * j] + 1); // 拿到所有划分区间内的最⼩值
}
// 返回结果
return dp[n];
}