279. 完全平方数

题目:

思路:

【1】动态规划的方式

【2】数学公式的方式(依据  四平方和定理

同时四平方和定理包含了一个更强的结论:
当且仅当 n≠4^k×(8m+7) 时,n 可以被表示为至多三个正整数的平方和。
因此,当 n=4^k×(8m+7) 时,n 只能被表示为四个正整数的平方和。此时我们可以直接返回 4。

当 n≠4^k×(8m+7) 时,我们需要判断到底多少个完全平方数能够表示 n,我们知道答案只会是 1,2,3 中的一个:
    答案为 1 时,则必有 n 为完全平方数,这很好判断;
    答案为 2 时,则有 n=a^2+b^2,我们只需要枚举所有的 a(1≤a≤√n),判断 n-a^2 是否为完全平方数即可;
答案为 3 时,我们很难在一个优秀的时间复杂度内解决它,故只需要检查答案为 12 的两种情况,即可利用排除法确定答案。

 

代码展示:

【1】动态规划的方式

//时间21 ms 击败 91.34%
//内存40.2 MB 击败 86.21%
//时间复杂度:O(n * √n),其中 n 为给定的正整数。
//状态转移方程的时间复杂度为 O(√n)[n的平方根],共需要计算 n 个状态,
//因此总时间复杂度为 O(n * √n)。
//空间复杂度:O(n)。我们需要 O(n) 的空间保存状态。
class Solution {
    public int numSquares(int n) {
        // 动态规划的方式列出从 1 - n 完全平方数的最少数量
        int[] f = new int[n+1];
        for (int i = 1; i <= n; i++){
            int minn = Integer.MAX_VALUE;
            for (int j = 1; j * j <= i; j++) {
                minn = Math.min(minn, f[i - j * j]);
            }
            f[i] = minn + 1;
        }
        return f[n];
    }
}

【2】数学公式的方式

//时间0 ms 击败 100%
//内存38.1 MB 击败 99.90%
class Solution {
    public int numSquares(int n) {
        if (isPerfectSquare(n)) {
            return 1;
        }
        if (checkAnswer4(n)) {
            return 4;
        }
        for (int i = 1; i * i <= n; i++) {
            int j = n - i * i;
            if (isPerfectSquare(j)) {
                return 2;
            }
        }
        return 3;
    }

    // 判断是否为完全平方数
    public boolean isPerfectSquare(int x) {
        int y = (int) Math.sqrt(x);
        return y * y == x;
    }

    // 判断是否能表示为 4^k*(8m+7)
    public boolean checkAnswer4(int x) {
        while (x % 4 == 0) {
            x /= 4;
        }
        return x % 8 == 7;
    }
}
posted @ 2023-08-01 12:09  忧愁的chafry  阅读(39)  评论(0编辑  收藏  举报