279-完全平方数

#include <iostream>
#include <vector>
#include <queue>

using namespace std;


class Solution {
public:
    int numSquares(int n) {
        int res = 0;
        if(n <= 0) return 0;

        queue< pair<int,int> > q;
        // 如果访问过了,就放弃第二次访问
        vector<bool> visited(n+1,false);
        q.push(make_pair(n,0));

        while(!q.empty()){
            int num = q.front().first;
            int step = q.front().second;
            q.pop();

            for(int i=0; ; i++){
                int a = num - i*i;
                if(a<0) break;
                if (a==0) return step+1;
                if (!visited[a]){
                    q.push( make_pair(a,step+1));
                    visited[a]=true;
                }
            }

        }

        return res;
    }
};

int main() {

    int res = Solution().numSquares(9);

    cout<<res<<endl;

    std::cout << "Hello, World!" << std::endl;
    return 0;
}

把这个问题转换为一个无权图找最短路径以后,因为有很多路径可以到达一个同一个节点(12–(1)–11–(4)–7、12–(4)–8--(1)–7),比如12就可以通过两个路径同时到达7,这时我们只需要push到队列中一个7即可,

比如12,在第三层的时候,就可以从不同的路径到达7-2,如果不加限制的话,队列中就会推入两个7和2,这个冗余度会随着n的增大迅速增大,然后造成内存饱满

// 动态规划
/*这里使用动态规划来做。时间复杂度O(nlogn),空间复杂度O(n)。代码非常精简 定义一个函数f(n)表示我们要求的解。f(n)的求解过程为: f(n) = 1 + min{ f(n-1^2), f(n-2^2), f(n-3^2), f(n-4^2), ... , f(n-k^2) } //(k为满足k^2<=n的最大的k) f(n) 存储了 组成完成n所需的最小完全平方数,f(1) = 1,f(2) = 2 ... f(5) = 2,f(6) = 3, */
int numSquares(int n) {
        int dp[n+1];
        memset(dp,0,n+1);
        for(int i=1; i<=n; i++){
            int minval = INT_MAX;
            for(int j =1; j*j<=i ;j++){
                minval = min(minval,dp[i-j*j]);
            }
            dp[i] = minval+1;
        }
        return dp[n];
    }