[leetcode] 279. Perfect Squares

441 篇文章 0 订阅
284 篇文章 0 订阅

Description

Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, …) which sum to n.

Example 1:

Input:

n = 12

Output:

3 

Explanation:

12 = 4 + 4 + 4.

Example 2:

Input:

n = 13

Output:

2

Explanation:

13 = 4 + 9.

分析

题目的意思是:把一个数分为几个数的平方和。

  • 这道题目用了四数平方和定理,当然另一种解法是动态规划,这里介绍四数平方和定理,任意一个正整数均可表示为4个正整数的平方和,即结果只有1,2,3,4中的一个;然后可以化简,如果一个数里面含有因子4,可以除掉,不影响结果,自己验证;如果一个数除以8余7,则这个数肯定由四个数平方和组成,证明略;接下来我们就只需要判断是1,2,3个整数的平方和了。判断1个和2个整数的平方和很好判断,如代码,如果都不是那就是3个啦,如最后一行代码。

C++代码

class Solution {
public:
    int numSquares(int n) {
        while(n%4==0) n=n/4;
        if(n%8==7) return 4;
        for(int a=0;a*a<n;a++){
            int b=sqrt(n-a*a);
            if(a*a+b*b==n){
                return !!a+!!b;
            }
        }
        return 3;
    }
};

Python

如果预先把所有可能值得平方求出来,这道题就变成了一个经典的dp问题了,然后就可以套用递推公式:

dp[i][j]=min(dp[i-1][j],dp[i][j-nums[i-1]]+1)

class Solution:
    def numSquares(self, n: int) -> int:
        # dp[i][j]=min(dp[i-1][j],dp[i][j-nums[i-1]]+1)
        squares = []
        i=1
        while(i*i<=n):
            squares.append(i*i)
            i+=1
        m = len(squares)
        dp = [[n]*(n+1) for i in range(m+1)]
        dp[0][0]=0
        for i in range(1,m+1):
            dp[i][0]=0
            for j in range(n+1):
                if j-squares[i-1]>=0:
                    dp[i][j]=min(dp[i-1][j],dp[i][j-squares[i-1]]+1)
                else:
                    dp[i][j]=dp[i-1][j]
        return dp[m][n]

下面的解法比较简洁,但不易想到:

class Solution:
    def numSquares(self, n: int) -> int:
        dp = [0]*(n+1)
        dp[1]=1
        for i in range(2,n+1):
            j = 1
            dp[i]=i
            while j*j<=i:
                dp[i]=min(dp[i],dp[i-j*j]+1)
                j+=1
        return dp[n]

参考文献

[LeetCode] Perfect Squares 完全平方数
Summary of 4 different solutions (BFS, DP, static DP and mathematics)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

农民小飞侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值