[LeetCode]problem 279. Perfect Squares

TAG

动态规划广度优先搜索深度优先搜索

数论四平方和定理三平方和定理

题目链接

方法

不会。不过是一道太有意思的题目了…

参见Summary of 4 different solutions (BFS, DP, static DP and mathematics).

首先是DP方法,设R[i]表示数i最少可由R[i]个数的完全平方和构成。那么递推关系可以写作:

R[i] = min( R[i-j*j] + 1 ), 0 < j*j <= i
R[0] = 0   

对我而言,是在是太巧妙了。R[i]的前一个状态,就是减掉一个数的平方和,结果值对应的那个状态。真是厉害啊。

接着是BFS。BFS首先把小于N的完全平方和作为图上的节点。每一步,对当前图的每一个节点向外扩展一步,就是将该节点与小于N的平方和挨个做加,如果等,则路径长度就是平方和的个数,如果小于,则产生一个新的节点;如果大于,则丢弃。迭代遍历,直到相等。

DFS,我自己想的… 没有写代码,不过应该可行。就是和之前的回溯一样的思想。同样产生小于N的所有平方和,然后把问题转化为找K个数,使得k个数的和为目标值。只不过为了保证是最少,需要从大往小遍历,且数可重复。遍历过程可剪枝。这么应该还是可行的。

最后,就是神奇的数学方法了。

  1. 四平方和定理:任意一个正整数都可以表示为4个数的平方和;

  2. 三平方和定理: 如果一个正整数可以表示为4^{a} * (8*b + 7),那么这个数一定不能表示为3个数的平方和。此时一定需要4个数的平方和相加才能表示(在维基百科上没有看到)。

  3. 处理2数的平方和,只需i1sqrt(n) , 看 n - i^2是否是完全平方即可。

代码

只写了DP方法。

class Solution {
public:
    int numSquares(int n) {
        if(n <= 0){ return 0 ;}
        vector<int> leastNum(n+1, numeric_limits<int>::max());
        leastNum[0] = 0;
        for(int i = 1; i < n + 1; ++i)
        {
            for(int testNum = 1; testNum * testNum <= i; ++testNum)
            {
                int preStateIdx = i - testNum * testNum;
                leastNum[i] = min( leastNum[preStateIdx] + 1, leastNum[i]);
            }
        }
        return leastNum.back();
    }
};

你可能感兴趣的:(找工作,leetcode)