|
1 | 1 | // https://leetcode.com/problems/perfect-squares
|
2 |
| -// T: O(N * k) k = size of perfect squares array which is constant |
3 |
| -// S: O(N + k) |
| 2 | +// T: O(k + sqrt(n)) k = size of perfect squares set which is constant |
| 3 | +// S: O(k) |
| 4 | + |
| 5 | +import java.util.Set; |
4 | 6 |
|
5 | 7 | public class PerfectSquares {
|
6 |
| - private static final int[] PERFECT_SQUARES = { |
| 8 | + private static final Set<Integer> PERFECT_SQUARES = Set.of( |
7 | 9 | 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576,
|
8 | 10 | 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849,
|
9 | 11 | 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721,
|
10 | 12 | 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241,
|
11 | 13 | 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409,
|
12 |
| - 9604, 9801, 10000, 10_201 |
13 |
| - }; |
| 14 | + 9604, 9801, 10_000, 10_201 |
| 15 | + ); |
14 | 16 |
|
15 |
| - public int numSquares(int n) { |
16 |
| - final int[] dp = new int[n + 1]; |
17 |
| - dp[0] = dp[1] = 1; |
18 |
| - for (int i = 2 ; i < dp.length ; i++) { |
19 |
| - dp[i] = numSquares(i, dp); |
20 |
| - } |
21 |
| - return dp[dp.length - 1]; |
| 17 | + private boolean isSquare(int n) { |
| 18 | + return PERFECT_SQUARES.contains(n); |
22 | 19 | }
|
23 | 20 |
|
24 |
| - private int numSquares(int n, int[] dp) { |
25 |
| - int result = Integer.MAX_VALUE, square; |
26 |
| - for (int i = 0 ; PERFECT_SQUARES[i] <= n ; i++) { |
27 |
| - square = PERFECT_SQUARES[i]; |
28 |
| - result = Math.min(result, dp[square] + dp[n - square]); |
| 21 | + // Based on Lagrange's Four Square theorem, there |
| 22 | + // are only 4 possible results: 1, 2, 3, 4. |
| 23 | + int numSquares(int n) { |
| 24 | + // If n is a perfect square, return 1. |
| 25 | + if (isSquare(n)) return 1; |
| 26 | + |
| 27 | + // The result is 4 if and only if n can be written in the |
| 28 | + // form of 4^k*(8*m + 7). Please refer to |
| 29 | + // Legendre's three-square theorem. |
| 30 | + while (n % 4 == 0) { |
| 31 | + n >>= 2; |
29 | 32 | }
|
30 |
| - return result; |
| 33 | + if (n % 8 == 7) return 4; |
| 34 | + |
| 35 | + // Check whether 2 is the result. if number can be composed as a^2 + b^2 |
| 36 | + for(int i = 1; i * i <= n; i++) { |
| 37 | + if (isSquare(n - i * i)) { |
| 38 | + return 2; |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + return 3; |
31 | 43 | }
|
32 | 44 | }
|
0 commit comments