LeetCode 279: Perfect Squares
-
- [1. 📌 Problem Links](#1. 📌 Problem Links)
- [2. 🧠 Solution Overview](#2. 🧠 Solution Overview)
- [3. 🟢 Solution 1: Dynamic Programming (Bottom-Up)](#3. 🟢 Solution 1: Dynamic Programming (Bottom-Up))
-
- [3.1. Algorithm Idea](#3.1. Algorithm Idea)
- [3.2. Key Points](#3.2. Key Points)
- [3.3. Java Implementation](#3.3. Java Implementation)
- [3.4. Complexity Analysis](#3.4. Complexity Analysis)
- [4. 🟡 Solution 2: Optimized Dynamic Programming](#4. 🟡 Solution 2: Optimized Dynamic Programming)
-
- [4.1. Algorithm Idea](#4.1. Algorithm Idea)
- [4.2. Key Points](#4.2. Key Points)
- [4.3. Java Implementation](#4.3. Java Implementation)
- [4.4. Complexity Analysis](#4.4. Complexity Analysis)
- [5. 🔵 Solution 3: Mathematical Approach (Lagrange's Four-Square Theorem)](#5. 🔵 Solution 3: Mathematical Approach (Lagrange's Four-Square Theorem))
-
- [5.1. Algorithm Idea](#5.1. Algorithm Idea)
- [5.2. Key Points](#5.2. Key Points)
- [5.3. Java Implementation](#5.3. Java Implementation)
- [5.4. Complexity Analysis](#5.4. Complexity Analysis)
- [6. 📊 Solution Comparison](#6. 📊 Solution Comparison)
- [7. 💡 Summary](#7. 💡 Summary)
1. 📌 Problem Links
- LeetCode 279 : Perfect Squares
2. 🧠 Solution Overview
This problem requires finding the minimum number of perfect square numbers that sum to a given integer n. A perfect square is an integer that is the square of an integer (e.g., 1, 4, 9, 16). Below are the main approaches:
| Method | Key Idea | Time Complexity | Space Complexity |
|---|---|---|---|
| Dynamic Programming | DP array storing min squares for each number | O(n√n) | O(n) |
| Space-Optimized DP | Similar but more efficient implementation | O(n√n) | O(n) |
| Mathematical Approach | Using Lagrange's four-square theorem | O(√n) | O(1) |
3. 🟢 Solution 1: Dynamic Programming (Bottom-Up)
3.1. Algorithm Idea
We use a DP array where dp[i] represents the minimum number of perfect squares that sum to i. The key insight is that any number i can be expressed as i = (i - j×j) + j×j for some j, where j×j is a perfect square. Therefore, the solution for i depends on solutions for smaller numbers .
3.2. Key Points
- State Definition :
dp[i]= minimum perfect squares that sum toi - State Transition :
dp[i] = min(dp[i], dp[i - j×j] + 1)for alljwherej×j ≤ i - Initialization :
dp[0] = 0(base case: 0 requires 0 squares)- Initialize all other
dp[i]to a large value (e.g.,Integer.MAX_VALUE)
- Processing Order: Process numbers from 1 to n sequentially
3.3. Java Implementation
java
class Solution {
public int numSquares(int n) {
// Create DP array with initial large values
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0; // Base case
// Precompute all perfect squares up to n
int maxSquare = (int) Math.sqrt(n);
int[] squares = new int[maxSquare + 1];
for (int i = 1; i <= maxSquare; i++) {
squares[i] = i * i;
}
// Fill DP table
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= maxSquare; j++) {
if (squares[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - squares[j]] + 1);
}
}
}
return dp[n];
}
}
3.4. Complexity Analysis
- Time Complexity : O(n√n) - Outer loop O(n), inner loop O(√n)
- Space Complexity : O(n) - For the DP array
4. 🟡 Solution 2: Optimized Dynamic Programming
4.1. Algorithm Idea
This is a more optimized version that eliminates the need to precompute all perfect squares. It uses the same DP concept but with more efficient inner loop conditions .
4.2. Key Points
- Direct Computation : Calculate
j×jon the fly instead of precomputing - Early Termination : Inner loop runs only while
j×j ≤ i - Efficient Initialization : Initialize
dp[i] = i(worst case: all 1's)
4.3. Java Implementation
java
class Solution {
public int numSquares(int n) {
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
// Worst case: all 1's (i = 1+1+...+1)
dp[i] = i;
// Try all perfect squares ≤ i
for (int j = 1; j * j <= i; j++) {
dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
}
}
return dp[n];
}
}
4.4. Complexity Analysis
- Time Complexity : O(n√n) - Same as previous DP approach
- Space Complexity : O(n) - For the DP array
5. 🔵 Solution 3: Mathematical Approach (Lagrange's Four-Square Theorem)
5.1. Algorithm Idea
This approach uses Lagrange's four-square theorem, which states that every natural number can be represented as the sum of four integer squares. The algorithm checks if the number can be represented by 1, 2, or 3 squares before defaulting to 4 .
5.2. Key Points
- Check for 1 square : If
nis a perfect square, return 1 - Check for 4 squares : If
n = 4^k × (8m + 7)for some k, m, return 4 - Check for 2 squares : Try all
ifrom 1 to √n to see ifn - i²is a perfect square - Default case: If none of the above, return 3
5.3. Java Implementation
java
class Solution {
public int numSquares(int n) {
// Check if n is a perfect square
if (isPerfectSquare(n)) {
return 1;
}
// Check four-square condition: n = 4^k × (8m + 7)
if (isFourSquare(n)) {
return 4;
}
// Check if n is sum of two squares
for (int i = 1; i * i <= n; i++) {
if (isPerfectSquare(n - i * i)) {
return 2;
}
}
// Default to three squares
return 3;
}
private boolean isPerfectSquare(int num) {
int sqrt = (int) Math.sqrt(num);
return sqrt * sqrt == num;
}
private boolean isFourSquare(int n) {
while (n % 4 == 0) {
n /= 4;
}
return n % 8 == 7;
}
}
5.4. Complexity Analysis
- Time Complexity : O(√n) - Much faster than DP approaches
- Space Complexity : O(1) - Constant space
6. 📊 Solution Comparison
| Solution | Time | Space | Pros | Cons |
|---|---|---|---|---|
| Standard DP | O(n√n) | O(n) | Intuitive, guaranteed optimal | Slower for large n |
| Optimized DP | O(n√n) | O(n) | More efficient, simpler code | Still polynomial time |
| Mathematical | O(√n) | O(1) | Optimal time, elegant | Harder to understand |
7. 💡 Summary
For the Perfect Squares problem:
- Learning & Understanding : Start with Standard DP to grasp the fundamental pattern
- Interviews & Practical Use : Optimized DP offers the best balance of understandability and efficiency
- Production & Performance : Mathematical Approach provides optimal O(√n) performance
The key insight for DP is recognizing the optimal substructure - the solution for each number can be built from solutions for smaller numbers by considering all possible perfect squares .
The search for perfect squares reveals the beautiful interplay between mathematical theory and computational practice - where deep number theory theorems can provide elegant solutions to seemingly complex optimization problems.