题目要求

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

For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.

判断一个数字最少由几个平方数的和构成。比如12=9+1+1+1=4+4+4,那么最少的数量为3。

思路一:暴力递归

要想知道什么样的组合最好,暴力比较所有的结果就好啦。当然,效率奇差。

    public int numSquares(int n) {
        if(n==0) return 0;
        if(n==1) return 1;
        int sqrt = (int) Math.floor(Math.sqrt(n));
        int count = Integer.MAX_VALUE;
        while(sqrt>0){
            int tmpCount = 0;
            int copy = n;
            do{
                copy -= sqrt * sqrt;
                tmpCount++;
            }while(copy > sqrt * sqrt);
            count = Math.min(count, tmpCount+numSquares(copy));
            sqrt--;
        }
        return count;
    }

思路二:动态规划

我们可以用另一种思路来拆解n:
比如:
numSquares(1) = 1;
numSquares(2) = numSquares(1)+1
numSquares(3) = numSquares(3-1*1) + 1
numSquares(4) = 1
numSquares(5) = min(numSquares(5-1*1)+1, numSquares(5-2*2)+1)
numSquares(10) = min(numSquares(10-1*1)+1, numSquares(10-2*2)+1, numSquares(10-3*3)+1)

这样我们就可以省去许多重复的计算。
代码如下:

    public int numSquares_dp(int n){
        if(n<=1) return n;
        int[] min = new int[n+1];
        min[1] = 1;
        for(int i = 2 ; i<=n ; i++){
            int sqrt = (int)Math.floor(Math.sqrt(i));
            int tempMin = Integer.MAX_VALUE;
            while(sqrt-->0){
                tempMin = Math.min(tempMin, min[n-sqrt*sqrt]);
                sqrt--;
            }
            min[i] = tempMin;
        }
        return min[n];
    }

思路三:数学统治一切

这里涉及了一个叫做四平方定理的内容。有兴趣的可以去了解一下这个定理。总之就是给了一个一般规律,这里贴上代码:

    public int numSquares_math(int n){
        if(isSquare(n)) return 1;
         while ((n & 3) == 0) // n%4 == 0  
            {
                n >>= 2;  
            }
            if ((n & 7) == 7) // n%8 == 7
            {
                return 4;
            }
            
            // Check whether 2 is the result.
            int sqrt_n = (int)(Math.sqrt(n)); 
            for(int i = 1; i <= sqrt_n; i++)
            {  
                if (isSquare(n - i*i)) 
                {
                    return 2;  
                }
            }  
            
            return 3; 
    }
    

clipboard.png
想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注我的微信公众号!将会不定期的发放福利哦~


raledong
2.7k 声望2k 粉丝

心怀远方,负重前行