文章目录

1.题目

【LeetCode279】完全平方数(完全背包问题)_状态转移

2.思路

并没有让你输出所有满足情况的具体方案,问的是满足情况的(最少数目的)时的【平方数最少的数量】,这种问题就是用dp了,和之前的拼硬币一样(每种币值的硬币不限量)是完全背包问题。
动态规划其实也就是遍历,只不过将中间值用空间储存起来了,便于计算了.

(1)确定状态
dp[i] 表示和为 i 的 nums 组合中完全平方数最少有 dp[i] 个.

(2)转移方程
确定状态转移方程需要2个意识:1)最后一步;2)子问题。
本题在​dp入门​中有讲,确定状态转移方程,如:若只有2元、5元、7元,现要拼成x元,状态转移方程就是【LeetCode279】完全平方数(完全背包问题)_python_02。具体转移方程见代码。

(3)初始条件+边界情况
初始化大小为n+1的数组,并且每个数组元素为0;特别的,n为0是数组元素值也是0。

(4)计算顺序
i和j都是从小到大。

3.C++代码

class Solution {
public:
int numSquares(int n) {
vector<int>dp(n+1, INT_MAX);
dp[0] = 0;
for(int i = 1; i * i <= n; i++){//遍历物品
for(int j = 1; j <= n; j++){
if(j - i * i >= 0){
dp[j] = min(dp[j - i * i] + 1, dp[j]);
}
}
}
return dp[n];
}
};

4.Python代码

class Solution:
import math
def numSquares(self, n: int) -> int:
#dp[i] 表示和为 i 的 nums 组合中完全平方数最少有 dp[i] 个。
dp = [float('inf')]*(n+1)
dp[0] = 0
#可供选则的nums列表 [1,4,9,...,sqrt(n)] 从中任意挑选数字组成和为n
#完全背包
for i in range(1, int(math.sqrt(n))+1):
for j in range(n+1):
if(j - i * i >= 0):
dp[j] = min(dp[j], dp[j-i*i]+1)
return dp[n]

注意python中可以用这种方式表示正无穷和负无穷:

float("inf"), float("-inf")

Reference

​一文吃透动态规划​