leetcode 279. 完全平方数

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


示例 1:

输入: n = 12
输出: 3 
解释: 12 = 4 + 4 + 4.
示例 2:

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


广度优先搜索

class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 0:
            return 0
        queue = deque([n])
        visited = set()
        path = 0
        while queue:
            path += 1
            length = len(queue)
            for i in range(length):
                num = queue.popleft()
                for j in range(1, int(num**0.5+1)):
                    x = num - j*j
                    if x == 0:
                        return path
                    if x not in set():
                        queue.append(x)
                        visited.add(x)
        return None

解析:https://leetcode-cn.com/problems/perfect-squares/solution/dong-tai-gui-hua-bfs-zhu-xing-jie-shi-python3-by-2/

遍历所有的可能组合是比较直观的一种方式。但是暴力的遍历显然是不行的,一旦当n较大时就肯定会耗费大量的时间。这里遍历设计的是采用队列的方式,用广度优先的方式来搜索。这样做的好处是一旦在某一层得到我们想要的答案,就能立马返回结果,不需要进行后面的计算。因为每一层列举了所有的组合可能,如果这一层的某一个路径符合答案,那么就不需要进行后面层的遍历。

这里用到的一个小技巧是用一个set来保存所有已经出现过的节点值,当遍历到的节点值是前面已经访问过的节点值,即具有相同的值,此时就不对其进行入队操作,因为相同节点一定是出现在当前节点之前,可能是当前层的,也可能是前面层的,那么该节点在前面都不符合要求,在这里更不会符合要求,因为层更深,如果该节点符合要求,选择的也不会是这个点而是前面的点。所以利用这个集合set可以减少大量的计算,这也是这种遍历方法可行的最大原因,相比于暴力解法每种都尝试。

动态规划

class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        dp = [i for i in range(n+1)]
        for i in range(2,n+1):
            for j in range(1,int(i**0.5)+1):
                dp[i] = min(dp[i],dp[i-j*j]+1)
        return dp[-1]

想到动态规划解题是相对容易的,但是如何确定状态转移方程是比较难的。对于dp[i]而言表示的是对于数字i,其最少的完全平方数。那么i其实可以分解为两部分,i = x + j*j,其中j是完全平方数,那么此时的总数就变成了dp[x]+1,dp[x]是组成x的最少完全平方数。那么我们只需要遍历所有j的可能,就能获得dp[i]。

在初始化dp数组的时候,可以先将其设为最多的完全平方数,那么就是全部都由1组成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值