Compile Ready
Module 6 · Decision Dynamic Programming

Perfect Squares

MediumProblem 22 of 30 8 min read ~20 min to solve LeetCode
Dynamic ProgrammingDecision DPUnbounded KnapsackMathMinimum Count
Asked atAmazonGoogleMicrosoftMetaAppleAdobe

Problem Statement

Given an integer n, return the least number of perfect square numbers whose sum is n. A perfect square is an integer of the form k * k, such as 1, 4, 9, or 16.

Input

A single integer n.

Output

An integer: the minimum number of perfect squares that sum to n.

Constraints

  • 1 <= n <= 10000

Examples

Example 1

Input:
n = 12
Output: 3
Explanation: 12 can be written as 4 + 4 + 4, so three squares are enough. No two perfect squares sum to 12.

Example 2

Input:
n = 13
Output: 2
Explanation: 13 can be written as 4 + 9.

Example 3

Input:
n = 1
Output: 1
Explanation: The number 1 is already a perfect square.

Learning Objectives

  • Recognise perfect squares as reusable pieces for building every amount up to **n**.
  • Define **dp[i]** as a minimum count rather than a boolean reachability state.
  • Derive the recurrence by choosing the last square used in the sum.
  • Connect the problem to unbounded knapsack because each square may be used repeatedly.

Intuition

For any target amount i, imagine the last square you decide to use. If that square is k * k, then the remaining amount is i - k * k. The best way to finish that remainder is already stored in dp[i - k * k] once we process amounts from small to large.

So every square gives one candidate answer: solve the remainder optimally, then add this one square. The minimum over all square choices is the best answer for i.

This is unbounded-knapsack-flavoured because using a square does not consume it. After taking 4 once, the subproblem may take 4 again, which is exactly how 12 becomes 4 + 4 + 4.

Common mistakes

  • ×Using a greedy largest-square-first strategy; for many values, the locally largest square does not prove optimality.
  • ×Forgetting **dp[0] = 0**, the base that makes an exact square cost one piece.
  • ×Initialising every **dp[i]** to 0, which makes unsolved states look better than real candidates.
  • ×Treating each perfect square as usable only once, even though the same square can appear multiple times.
  • ×Looping only over square values already less than **n** and accidentally missing the case where **i** itself is a square.

State Definition

Let dp[i] be the minimum number of perfect squares needed to sum exactly to i. The answer is dp[n].

State Transition

For each amount i, try every square k * k <= i as the last chosen piece:

dp[i] = min over k * k <= i of dp[i - k * k] + 1

The base case is dp[0] = 0 because zero squares are needed to make amount 0. All positive states start at a large sentinel value and are improved by valid square choices.

Solutions

Solution: Bottom-up minimum-count DP

When to prefer this:

Use this when the interviewer expects a DP derivation. It is deterministic, simple to justify, and mirrors the coin-change minimum-count pattern with square numbers as the coin set.

Build answers for amounts from 1 through n. For each amount, test every square not exceeding it. The candidate count is one chosen square plus the best count for the remaining amount. Keep the smallest candidate.

Step-by-step

  1. Create dp of size n + 1 and fill it with n + 1, a safe value larger than any possible answer.
  2. Set dp[0] = 0.
  3. For each amount from 1 to n, enumerate bases base while base * base <= amount.
  4. Let square = base * base and relax dp[amount] with dp[amount - square] + 1.
  5. Return dp[n] after all smaller amounts have been solved.
Time

O(n · sqrt(n))

Space

O(n)

Each amount tries all square numbers up to itself, and the table stores one value per amount.

Java implementation

Loading…

Dry Run

Sample input

n = 12. Build dp[amount] from 0 to 12 using square choices 1, 4, and 9 where applicable.

amountsquares triedbest expressiondp[amount]
0noneempty sum0
1111
211 + 12
311 + 1 + 13
41, 441
51, 44 + 12
61, 44 + 1 + 13
71, 44 + 1 + 1 + 14
81, 44 + 42
91, 4, 991
101, 4, 99 + 12
111, 4, 99 + 1 + 13
121, 4, 94 + 4 + 43

At amount 12, choosing square 4 leaves amount 8, whose best value is 2. Therefore dp[12] = dp[8] + 1 = 3.

Complexity Analysis

This is the same minimum-count template as unbounded coin change, with the candidate coin list restricted to perfect squares no larger than the current amount.

Bottom-up minimum-count DP

Time

O(n · sqrt(n))

Space

O(n)

Each amount tries all square numbers up to itself, and the table stores one value per amount.

Interview Tips

Name the similarity to Coin Change, but be explicit that the generated coins are 1, 4, 9, ... up to n. Explain why greedy is not the proof you want in a DP interview: the recurrence is what guarantees the global minimum. Keep the base case and sentinel initialisation clear before coding.

Likely follow-ups

  • How would you return one actual list of squares that achieves the minimum?
  • Can you solve the problem using shortest-path BFS over amounts?
  • What changes if only a limited quantity of each square is available?
  • How would number-theory results affect the asymptotic complexity?

Similar Problems

Key Takeaways

  • Minimum-count DP chooses one final piece and adds one to the solved remainder.
  • Perfect Squares is unbounded because the same square may be used repeatedly.
  • A large sentinel value prevents unsolved states from winning a minimum comparison.
  • The amount loop guarantees every remainder **i - square** has already been computed.
Reusable template: Unbounded minimisation DP: let dp[i] be the best cost for value i, try every reusable valid piece not exceeding i, and minimise dp[i - piece] plus one.