【算法题】279. 完全平方数-力扣(LeetCode)

【算法题】279. 完全平方数-力扣(LeetCode)

1.题目

下方是力扣官方题目的地址

279. 完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,14916 都是完全平方数,而 311 不是。

示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4

示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

提示:

  • 1 <= n <= 104

2.题解

思路

这是一道典型的动态规划中的完全背包题

完全背包示例:

背包容量 c=13

物品重量        w=[1,2,3,4,5]

所对应的价值 v=[2,3,4,5,8]

完全背包里面的物品可以无限选

求如何选价值最大

这当然是都选第一个,价值:26

我们将这题类比于完全背包

我们以n=12为例:

里面的n就是完全背包中的c(背包容量)

价值是什么呢?

我们要求最小数量,而每家一个物品,数量就加一,所以这里面 的价值v恒等于1,即:

v=1

这题要求求最小价值

那么物品重量是什么呢?

当然就是小于等于n的完全平方数了,即:

w=[1,2,4,9]

把这题转换成完全背包后,我们直接套模板就行了

直观Python代码

class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        ans=1
        w=[]
        v=1
        while ans**2<=n:
            w.append(ans**2)        # 生成完全平方数
            ans+=1
        dp=[[float('inf')]*(n+1) for _ in range(len(w)+1)]      # 初始化dp数组
        for i in range(len(w)+1):                               # 预处理一些已知的值
            dp[i][0]=0
        for i in range(1,len(w)+1):
            for j in range(1,n+1):                              # 套用模板
                dp[i][j]=dp[i-1][j]
                if j>=w[i-1]:dp[i][j]=min(dp[i][j],dp[i][j-w[i-1]]+v)
        return dp[-1][-1]

以上代码较为直观,但是比较复杂,我们可以对其进行优化:

优化思路

  1. 空间优化:由于动态规划的状态转移方程只依赖于前一行的数据,可以将二维数组优化为一维数组。
  2. 减少不必要的计算:在构建完全平方数列表时,可以直接使用一个列表来存储这些数,而不需要每次计算平方。

优化后的Python代码

class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        # 生成所有小于等于 n 的完全平方数
        w = [i * i for i in range(1, int(n**0.5) + 1)]
        v=1
        # 初始化一维动态规划数组
        dp = [float('inf')] * (n + 1)
        dp[0] = 0
        
        # 动态规划填表
        for i in w:
            for j in range(i, n + 1):
                dp[j] = min(dp[j], dp[j - i] + v)
        
        return dp[n]

优化点解释

  1. 生成完全平方数
    • 使用列表推导式 w = [i * i for i in range(1, int(n**0.5) + 1)] 直接生成所有小于等于 n 的完全平方数。
    • 这样可以避免在每次循环中计算平方,提高效率。
  2. 一维动态规划数组
    • 将二维数组 dp 优化为一维数组 dp,只保留当前行的状态。
    • 初始化 dp 数组,dp[0] 设为 0,表示组成 0 的最少完全平方数为 0。
    • 遍历每个完全平方数 i,更新 dp 数组中的值。
  3. 状态转移方程
    • 对于每个完全平方数 i,更新 dp[j] 的值,其中 jin
    • 状态转移方程为 dp[j] = min(dp[j], dp[j - i] + v),表示当前值 j 可以通过减去一个完全平方数 i 并加上 v 来得到。

3.结语

本人资历尚浅,发博客主要是记录与学习,欢迎大佬们批评指教!大家也可以在评论区多多交流,相互学习,共同成长。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值