# 279 Perfect Squares

給一個整數n,問最少幾個prefect squared number可以加總為n?

  • 思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 2 3 1 2 3 4 2 1 2 3 3 2 3 4 1

舉個例子觀察自己是怎麼思考的,

首先我把squared number直接標成1,

那我在算2的時候,會先把1(距離2最近的perfect squared)扣掉,再看dp[1]是多少,所以得到1+1 = 2

其他數字的計算也同理

例如: 7 = dp[4] + dp[3] = 1 + 3

所以我想用一個dp陣列,和一個儲存perfect squares的list來解題。

  • pseudo code

            a list to keep perfect squared numbers
            an array to record all numbers and their least number of perfect squared numbers
            for i=1:n
                if i is perfect squared,
                    add i to list,
                    array[i] = 1
                else
                    go through list j
                        min
                        if array[j] + array[i-j]
                            update min
                    array[i] = min
    
            return array[n-1]
    
  • Code

    public class Solution {
        public int numSquares(int n) {
            List<Integer> perfectSquared = new ArrayList<>();
            int[] dp = new int[n+1];
            dp[0] = 0;
            dp[1] = 1;
            perfectSquared.add(1);
            for(int i=2; i<n+1; i++){
                if(isPerfectSquared(i)){
                    perfectSquared.add(i);
                    dp[i] = 1;
                }else{
                    int min = Integer.MAX_VALUE;
                    for(int j=0; j < perfectSquared.size(); j++){
                        int k = perfectSquared.get(j);
                        if(dp[k] + dp[i-k] < min){
                            min = dp[k] + dp[i-k];
                        }
                    }
                    dp[i] = min;
                }
                //System.out.println(dp[i]);
            }
    
            return dp[n];
        }
    
        private boolean isPerfectSquared(int i){
            if((int)Math.sqrt(i) == Math.sqrt((double)i) )  return true;
            return false;
        }
    }
    
  • 分析:
    這個做法時間複雜度是O(n*n^(1/2)) = O(n^(3/2)) 空間用了額外的n^(1/2)
    想要更優化最好可以不用另外用List存perfect squared numbers。
    參考此作法

public int numSquares(int n) {
    int[] dp = new int[n + 1];
    Arrays.fill(dp, Integer.MAX_VALUE);
    dp[0] = 0;
    for(int i = 1; i <= n; ++i) {
        int min = Integer.MAX_VALUE;
        int j = 1;
        while(i - j*j >= 0) {
            min = Math.min(min, dp[i - j*j] + 1);
            ++j;
        }
        dp[i] = min;
    }        
    return dp[n];
}
  • 超優化寫法: Based on Legendre's three-square theorem, 所有數字都可以寫成3個perfect square的總和, 除非他可以表示成4^a(8b+7)
class Solution {
    public int numSquares(int n) {
        while (n % 4 == 0)
            n /= 4;
        if (n % 8 == 7)
            return 4;
        for (int a=0; a*a<=n; ++a) {
            int b = (int) Math.sqrt(n - a*a);
            if (a*a + b*b == n)
                return a == 0 ? 1 : 2;
        }
        return 3;
    }
}

results matching ""

    No results matching ""