LeetCode 279: Perfect Squares

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)

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 to i
  • State Transition : dp[i] = min(dp[i], dp[i - j×j] + 1) for all j where j×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×j on 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 n is 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 i from 1 to √n to see if n - 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.

相关推荐
yaoxin5211233 小时前
434. Java 日期时间 API - Period 基于日期的时间段
java·开发语言·python
noipp3 小时前
推荐题目:洛谷 P10907 [蓝桥杯 2024 国 B] 蚂蚁开会
c语言·c++·算法·编程·洛谷
何极光4 小时前
IDEA集成Maven
java·maven·intellij-idea
程序员二叉4 小时前
【JUC】ThreadLocal底层原理|内存泄漏|弱引用|跨线程传递方案
java·开发语言·面试·职场和发展·juc
程序员二叉4 小时前
【JUC】线程池全套深度详解|参数|流程|拒绝策略|调优|异常处理
java·开发语言·jvm·算法·面试·juc
老马识途2.04 小时前
在AI的帮助下理解spring的启动过程
java·前端·spring
青山木4 小时前
Hot 100 --- 轮转数组
java·数据结构·算法
徐小夕5 小时前
Loop Engineering 深度解析与实战指南(全网最全)
前端·算法·github
Qt程序员5 小时前
掌握 Linux 内核调度:从原理到实现(进程篇)
java·开发语言
code bean5 小时前
【LangChain】检索器完全指南:从向量检索到生产级 RAG 架构
java·开发语言·微服务