代码随想录动态规划——完全平方数

题目

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

给你一个整数 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 <= 10^4

思路

完全平方数相当于物品(可以无限使用),凑的正整数n就是背包,问凑满这个背包最少需要多少个物品(完全平方数)->完全背包

动规五部曲:

  1. 确定dp数组和下标的含义
    dp[j] :表示组成和为 j 需要的完全平方数的个数为dp[j]
  2. 确定递推公式
    dp[j]可以由dp[j-i*i]推导出来,即dp[j-i*i]+1即可凑成dp[j],此时需要选择最小的dp[j],所以递推公式为 dp[j] = min(dp[j],dp[j-i*i]+1)
  3. 初始化dp数组
    dp[0]表示组合和为0需要的完全平方数的个数为0,所以初始化为dp[0]=0,然后考虑非0下标的dp[j], 因为每次需要选最小的,所以dp[j]一定要初始化为最大值,才能在递推的过程中不被初始值覆盖(比如初始值为0,但是递推的结果为1,min(0,1) = 0就会出现无法覆盖的情况)
  4. 确定遍历顺序
    完全背包->
    (1)求组合数(正常)->外层for物品,内层for背包
    (2)求排列数(反着来)->外层for背包,内层for物品
    本题只是求最小数,没有明确要求,所以不要求先后顺序
  5. 举例推导dp数组
    当输入n=5时,dp状态图如下:
    代码随想录动态规划——完全平方数_第1张图片

java代码如下:

class Solution {
	//先遍历物品,再遍历背包容量
	public int numSquares(int n){
		int max = Integer.MAX_VALUE;
		int[] dp = new int[n+1];
		for(int j = 0; j <= n; j++){
			dp[j] = max;
		}
		dp[0] = 0;
		for(int i = 1; i*i <= n; i++){//遍历物品,这里i是1开始,i*i是对应的重量
			for(int j = i*i; j <= n; j++){//遍历背包容量
				if(dp[j-i*i] != max){//只有dp[j-i*i]不是初始最大值的时候,该位才有选择的必要
					dp[j] = Math.min(dp[j], dp[j-i*i]+1);//选择最小的情况
				}
			}
		}
		return dp[n];
	}
}

class Solution{
	//先遍历背包容量,再遍历物品
	public int numSquares(int n){
		int max = Integer.MAX_VALUE;
		int[] dp = new int[n+1];
		for(int j = 0; j <= n; j++){
			dp[j] = max;
		}
		dp[0] = 0;
		for(int j = 1; j<= n; j++){//先遍历背包容量
			for(int i = 1; i*i <= j; i++){//遍历物品,在外层for循环下,当前的背包容量为j
				dp[j] = Math.min(dp[j],dp[j- i*i]+1);
			}
		}
		return dp[n];
	}
}


你可能感兴趣的:(代码随想录,动态规划,算法,leetcode)