力扣Leetcode:279. 完全平方数

力扣Leetcode:279. 完全平方数_第1张图片

目录

解法一:动态规划

解法二:四平方和定理


解法一:动态规划

对于一个数n来说,要求完全平方数的数量,它的完全平方数必然在区间  (根号下n需要向下取整)。那么对于在这个区间内的数 m,必然满足

在这种情况下,n的完全平方数的数量(用 f(n) 表示)为:

要求最少的数量,那就要比较这个区间里的所有元素,找出一个最少的来,所以,令表示正整数n的最少数量的完全平方和。则

其中m=sqrt(n)向下取整。

c++代码:

class Solution {
public:
    int numSquares(int n) {
        int f[n+1];
        memset(f,0, sizeof(f));
        f[0] = 0;
        f[1] = 1;
        for(int i = 2; i <= n; i++){
            int m = sqrt(i);
            int min = 9999;
            for(int j = 1; j <= m; j++){
                int tmp = f[i-j*j] + 1;
                if(min > tmp){
                    min = tmp;
                }
            }
            f[i] = min;
        }
        return f[n];
    }
};

力扣Leetcode:279. 完全平方数_第2张图片

 

解法二:四平方和定理

定理内容:每个正整数均可表示成不超过四个整数的平方之和。

重要的推论:一个正整数 n, 如果只能被表示成四个整数的平方和,必定满足:

定理的证明:https://zhuanlan.zhihu.com/p/104030654

定理的内容以及推论:https://blog.csdn.net/l_mark/article/details/89044137

解决方案:

要求最少数量,根据分析只存在四种情况,最少数量m = 1,2,3,4。

  1. 判断m=1的情况,也就是n=a*a。
  2. 判断m=4的情况,也就是判断式子是否成立。
  3. 判断m=2的情况,也就是n=a*a+b*b。遍历区间1 <= i <= sqrt(n),判断n-i*i是否是完全平方数,如果是,则m=2。
  4. 其余情况,m=3。
class Solution {
public:
    int numSquares(int n) {
        int t = sqrt(n);
        if(t*t == n) return 1; //判断m=1
        t = n;
        while(t % 4 == 0){
            t = t / 4;
        }
        t = t % 8;
        if(t == 7) return 4; //判断m=4
        int m = sqrt(n);
        for(int i = 1; i <= m; i++){
            int a = i * i; 
            int b = sqrt(n-a);
            if(b*b == (n-a)) return 2; //判断m=3
        }
        return 3; //其余情况m=3
    }
};

力扣Leetcode:279. 完全平方数_第3张图片

下面是执行记录,第一个是解法二的,第二个是解法一的。

力扣Leetcode:279. 完全平方数_第4张图片

你可能感兴趣的:(leetcode,动态规划)