[LeetCode] 0279. Perfect Squares 完全平方数

题目

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

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

Example 1:

Input: n = 12
Output: 3 
Explanation: 12 = 4 + 4 + 4.

Example 2:

Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.

解法一

动态规划,这是比较慢的解法,这个坑先留着,现在主要是在做BFS的题。

class Solution {
public:
    int numSquares(int n) {
        if (n == 0) {
            return 0;
        }
        vector<int> steps(n + 1, INT_MAX);
        steps[0] = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j * j <= i; ++j) {
                steps[i] = min(steps[i], steps[i - j * j] + 1);
            }
        }
        return steps[n];
    }
};

解法二

最短路径,BFS

参考资料:https://blog.csdn.net/qq_17550379/article/details/80875782

思路:寻找最短路径嘛,肯定是用到广度优先搜索了,不断拆解队列中的数字,得到答案后直接返回就是最短路径了。具体的做法很简单,以下是具体BFS思路:

把n推入队列,然后取出来进行拆解(-1,-4,-9…),减掉后如果不等于0,就将余下来的值推入队列,等待第二轮搜索,如果减掉后等于0就是直接找到答案了,返回step+1即可,不需要再搜索下去了(记得要有visited昂,因为是个循环图)。

class Solution {
public:
    int numSquares(int n) {
        queue<pair<int, int>> q;
        // pair.first 代表将n拆解后的数字,pair.second代表所走的步数
        // 刚开始推入未拆解的n,步数为0
        q.push(make_pair(n, 0));

        bool visited[n + 1];
        memset(visited, 0, sizeof(visited));
        visited[n] = true;

        // 开始广度优先搜索
        while (!q.empty()) {
            // 取队头,进行拆解
            auto pair = q.front();
            q.pop();
            
            int i = 1;
            int next_num = pair.first - i * i;
            
            // 在推入队列前先看看能不能解答
            while (next_num >= 0) {
                if (next_num == 0) {
                    return pair.second + 1;
                }
                // 还有余数没扣完,就将可以的下一步都推入队列
                if (!visited[next_num]) {
                    q.push(make_pair(next_num, pair.second + 1));
                    visited[next_num] = true;
                }
                // 计算下一步
                i++;
                next_num = pair.first - i * i;
            }
        }
        return 0;
    }
};

运行结果:

Runtime: 16 ms, faster than 86.01% of C++ online submissions for Perfect Squares.
Memory Usage: 11.6 MB, less than 24.62% of C++ online submissions for Perfect Squares.

解法三

Lagrange四平方定理:任何一个正整数都可以表示成不超过四个整数的平方之和。 推论:满足四数平方和定理的数n(四个整数的情况),必定满足 n=4^a(8b+7)。

做计算机的数学也要好啊,这个定理告诉我们,这道题的答案无非只有1、2、3、4,而且如果满足上述公式,那么答案就是4,如果不能被1个或2个完全平方数组成,那么就返回3。

(真是暴力啊,逃……

class Solution {
public:
    int numSquares(int n) {
        // Lagrange四平方定理:任何一个正整数都可以表示成不超过四个整数的平方之和。
        // 推论:满足四数平方和定理的数n(四个整数的情况),必定满足 n=4^a(8b+7)。
        while (n % 4 == 0)
            n /= 4;

        if (n % 8 == 7)
            return 4;

        int a = 0;
        while (a * a <= n) {
            int b = (int)sqrt(n - a * a);
            if (a * a + b * b == n) {
                return (a ==0 || b == 0) ? 1 : 2;
            }
            a++;
        }
        return 3;
    }
};

运行结果:

Runtime: 0 ms, faster than 100.00% of C++ online submissions for Perfect Squares.
Memory Usage: 8.4 MB, less than 90.15% of C++ online submissions for Perfect Squares.
posted @ 2019-08-25 16:30  冰芒  阅读(147)  评论(0编辑  收藏  举报