目录
1.题目描述
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...
)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
2.解题思路
这个问题就是完全背包问题的简单变种,在这里,平方数sqr就是物品的重量weight,物品产生的价值val都是1。题目问的问题是,能让这m个物品装满空间为n的背包的方法中,产生价值最少的装法,所以把模板里的最大值改成最小值就行。
思路:
标签:动态规划
- 首先初始化长度为 n+1 的数组 dp,每个位置都为 0
- 如果 n 为 0,则结果为 0
- 对数组进行遍历,下标为 i,每次都将当前数字先更新为最大的结果,即 dp[i]=i,比如 i=4,最坏结果为 4=1+1+1+1 即为 4 个数字
- 动态转移方程为:dp[i] = MIN(dp[i], dp[i - j * j] + 1),i 表示当前数字,j*j 表示平方数
- 时间复杂度:O(n*sqrt(n))O(n∗sqrt(n)),sqrt 为平方根
3.源代码
1.直接套用完全背包的模板进行解题
class Solution {
public int numSquares(int n) {
int[] dp = new int[n + 1]; // 默认初始化值都为0
for (int i = 1; i <= n; i++) {
dp[i] = i; // 最坏的情况就是每次+1
for (int j = 1; i - j * j >= 0; j++) {
dp[i] = Math.min(dp[i], dp[i - j * j] + 1); // 动态转移方程
}
}
return dp[n];
}
}
Leetcode运行截图:
2.将问题分成两个步骤,首先枚举平方数,将平方数存入数组,然后遍历时将平方数当做背包问题的物品的重量。
private List<Integer> generateSquareList_1(int n){
List<Integer> squareList = new ArrayList<>();
int ans=1;
while(ans*ans<=n) {
squareList.add(ans * ans);
ans = ans + 1;
}
return squareList;
}
动态规划
public int numSquares(int n) {
int []dp=new int[n+1];
dp[0]=0;
List<Integer> list=generateSquareList(n);
for(int i=1;i<=n;i++){
int min = Integer.MAX_VALUE;
for(int num:list){
if(num>i){
break;
}
min = Math.min(min, dp[i - num] + 1);
}
dp[i]=min;
}
return dp[n];
}
运行结果:
提交Leetcode结果截图:
综合来看,这种方法的综合效率不是很高。
4.完全背包问题
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
示例1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例2:
输入:coins = [2], amount = 3
输出:-1
示例3:
输入:coins = [1], amount = 0
输出:0
示例4:
输入:coins = [1], amount = 1
输出:1
解题思路:这个题目就是完全背包的一个变种,总金额amount 就是背包的容量,硬币的coins就是背包的容量。然后我们套用完全背包的模板我们就可以解决问题。
public class Bag_01 {
public int change(int amount, int[] coins) {
int []dp=new int[amount+1];
//设置初始状态
dp[0]=1;
for(int coin:coins){
for(int j=1;j<=amount;j++){
if(j>=coin){
dp[j]=dp[j]+dp[j-coin];
}
}
}
return dp[amount];
}
public static void main(String[] args) {
int amount=5;
int []coin={1,2,5};
Bag_01 b=new Bag_01();
int ans=b.change(amount,coin);
System.out.println(ans);
}
}
运行截图:
Leetcode提交截图: