dp[n] = Min{ dp[n - i*i] + 1 }, for n - i*i >=0 && i >= 1
具体推理如下:
The most intuitive approach besides brute force would probably be dynamic programming, whether it's bottom up iteration or recursion with memoization, they all based on the recurrence relation:
j = i + (a perfect square number) or i = j + (a perfect square number)
已知起始点0,和终点n,这样问题就转化为一个最短路径问题。故使用BFS。
// Consider a graph which consists of number 0, 1,...,n as
// its nodes. Node j is connected to node i via an edge if
// and only if either j = i + (a perfect square number) or
// i = j + (a perfect square number). Starting from node 0,
// do the breadth-first search. If we reach node n at step
// m, then the least number of perfect square numbers which
// sum to n is m. Here since we have already obtained the
// perfect square numbers, we have actually finished the
// search at step 1.
Solution
Dynamic Programming - Iterative Bottom Up (~ 22ms AC)
classSolution {publicintnumSquares(int n) {int[] dp =newint[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]; }}
Mathematical - (1ms AC)
classSolution {// Based on Lagrange's Four Square theorem, there// are only 4 possible results: 1, 2, 3, 4.publicintnumSquares(int n) {// If n is a perfect square, return 1.if(is_square(n)) {return1; }// The result is 4 if and only if n can be written in the// form of 4^k*(8*m + 7). Please refer to// Legendre's three-square theorem.while ((n &3) ==0) // n%4 == 0 { n >>=2; }if ((n &7) ==7) // n%8 == 7 {return4; }// Check whether 2 is the result.int sqrt_n = (int)(Math.sqrt(n));for(int i =1; i <= sqrt_n; i++) {if (is_square(n - i*i)) {return2; } }return3; }privatebooleanis_square(int num) {int sqrt_num = (int) Math.sqrt(num);return sqrt_num * sqrt_num == num; }}
Recursion Memoization (NOT RECOMMENDED) - (655ms AC 4.86% percentile)