LeetCode - 279. Perfect Squares

题目

LeetCode - 279. Perfect Squares

题目链接

https://leetcode.com/problems/perfect-squares/

参考博客

https://www.cnblogs.com/grandyang/p/4800552.html

解题思路

本题解法参考上述博客。

1. 解法一:四平方和定理

根据四平方和定理知,任何正整数可表示成四个整数的平方和。那么本次的答案只有可能是1,2,3,4其中一种。一开始用n % 4简化n(这个没看懂),然后用n % 8 == 7选出结果4,接着用!!i + !!j选出12,剩下的是33是补集,正推不知道如何做,此解法只看懂了选出结果12的,二刷时再仔细研究。

2. 解法二:动态规划

参考博客解法二,这里解释一下递推公式, d p ( n ) = m i n ( d p ( n ) , d p ( ( n − m ) + 1 ) dp(n) = min(dp(n), dp((n - m) + 1) dp(n)=min(dp(n),dp((nm)+1),其中 d p ( n ) dp(n) dp(n)表示从 [ 1 , n ] [1,n] [1,n] k k k个平方数 a i . . . a i + k a_i...a_{i+k} ai...ai+k,并且是 k k k最小, m m m表示小于 n n n的一个平方数。因此 d p ( n ) dp(n) dp(n)的值只有可能是这两种,一种是没有比 n n n小的平方数了,那么值便是它本身,另一种是若有比 n n n小的平方数,最终值可能是新值 n − m n - m nm d p ( n − m ) dp(n - m) dp(nm)再加1(指 m m m)。

分析解法一和解法二的复杂度:

解法时间复杂度空间复杂度
解法一 O ( l o g ( n ) ) O(log(n)) O(log(n)) O ( 1 ) O(1) O(1)
解法二 O ( n 3 2 ) O(n^{\frac 3 2}) O(n23) O ( n ) O(n) O(n)
解法三:递归

参考博客的递归方法很简洁,暂且先不看,此处贴出自己写的递归算法,但是提交LeetCode报时间超限,先贴出来,二刷时再详细研究。

解题源码
1. 解法一代码
class Solution {
public:
    int numSquares(int n) {
        while (n % 4 == 0) n /= 4;
        if (n % 8 == 7) return 4;
        for (int i = 0; i*i <= n; i++){
            int j =  static_cast<int>(sqrt(n - i * i));
            if (i*i + j*j == n) return !!i + !!j;
        }
        return 3;
    }
};
2. 解法二代码
class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 0; i <= n; i++){
            for (int j = 0; j * j <= n - i; j++){
                dp[i + j * j] = min(dp[i + j * j], dp[i] + 1);
            }
        }
        return dp[n];
    }
};
3. 解法三代码
class Solution {
public:
    int minpath = INT_MAX;
    int tmppath = 0;
    // vector<int> tmp;
    void dfs(int n, int ulimit){
        if (n < 0) return ;
        if (n == 0){
        	// for (auto it :tmp){
        	// 	cout << it << " ";
        	// }
        	// cout << endl;
        	// printf("tmppath = %d\n", tmppath);
            minpath = min(minpath, tmppath);
            return ;
        }
        
        for (int t = ulimit; t > 0; --t){
            tmppath++;
            // tmp.push_back(t*t);
            dfs(n - t*t, static_cast<int>(t));
            tmppath--;
            // tmp.pop_back();
        }
    }
    int numSquares(int n) {
        dfs(n,static_cast<int>(sqrt(n)));
        return minpath;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值