You are given an integer array matchsticks where matchsticks[i] is the length of the ith matchstick. You need to use all the matchsticks to make one square. You should not break any stick, but you can link them up, and each matchstick must be used exactly one time.
Return true if you can make this square and false otherwise.
Please upgrade to NeetCode Pro to view company tags.
Prerequisites
Before attempting this problem, you should be comfortable with:
Backtracking - Used to explore all possible ways to partition matchsticks into 4 equal groups
Recursion - Understanding recursive function calls and how to backtrack by undoing choices
Bitmask Dynamic Programming - An optimization technique using binary representation to track subsets of used elements
1. Backtracking (Brute Force)
Intuition
To form a square, we need to partition matchsticks into 4 groups with equal sums. Each matchstick must be assigned to exactly one side. We try placing each matchstick on each of the 4 sides recursively. If we successfully place all matchsticks and all 4 sides have equal length, we found a valid square.
Algorithm
Calculate the total length. If not divisible by 4, return false immediately.
Create an array sides of size 4 to track the current length of each side.
Use backtracking: for each matchstick, try adding it to each of the 4 sides.
After placing a matchstick, recurse to place the next one.
If we place all matchsticks and all sides are equal, return true.
Backtrack by removing the matchstick from the current side before trying the next side.
classSolution{funcmakesquare(_ matchsticks:[Int])->Bool{let sum = matchsticks.reduce(0,+)if sum %4!=0{returnfalse}var sides =[Int](repeating:0, count:4)funcdfs(_ i:Int)->Bool{if i == matchsticks.count {return sides[0]== sides[1]&& sides[1]== sides[2]&& sides[2]== sides[3]}for j in0..<4{
sides[j]+= matchsticks[i]ifdfs(i +1){returntrue}
sides[j]-= matchsticks[i]}returnfalse}returndfs(0)}}
Time & Space Complexity
Time complexity: O(4n)
Space complexity: O(n) for recursion stack.
2. Backtracking (Pruning)
Intuition
The brute force approach explores many redundant paths. We can prune significantly with two optimizations. First, sort matchsticks in descending order so larger sticks are placed first, failing faster when a configuration is impossible. Second, skip trying to place a matchstick on an empty side if we already tried another empty side, since empty sides are interchangeable.
Algorithm
Calculate the total length and target side length. Return false if total is not divisible by 4.
Sort matchsticks in descending order for early pruning.
In the recursive function, try placing the current matchstick on each side:
Skip if adding the matchstick would exceed the target length.
If placement succeeds recursively, return true.
Backtrack by removing the matchstick.
If the current side is empty after backtracking, stop trying other sides (they are equivalent).
Return true if all matchsticks are placed successfully.
We can represent which matchsticks have been used with a bitmask. For each subset of matchsticks, we track the current "partial side" length (sum modulo target side length). If we can use all matchsticks such that each completed side reaches exactly the target length, we have a valid square. Memoization avoids recomputing results for the same subset.
Algorithm
Validate that the total length is divisible by 4 and no single matchstick exceeds the target side length.
Sort matchsticks in descending order for better pruning.
Use a DP array where dp[mask] stores the partial sum of the current incomplete side for that subset of used matchsticks.
Starting from the full bitmask, recursively try removing each matchstick:
If the resulting partial sum plus the matchstick does not exceed the target, update dp[mask].
Use modulo to reset when a side is completed.
Return true if dp[fullMask] == 0, meaning all sides completed perfectly.
Before attempting any backtracking, verify that the total sum of matchsticks is divisible by 4. Without this early check, the algorithm wastes time exploring configurations that can never form a valid square.
Missing the Single Matchstick Length Check
If any single matchstick is longer than the target side length (total / 4), it is impossible to form a square. Failing to check this upfront leads to unnecessary recursion and potential timeout.
Not Sorting Matchsticks in Descending Order
Sorting matchsticks in descending order significantly improves pruning efficiency. Placing larger matchsticks first causes invalid configurations to fail faster, reducing the search space dramatically. Without sorting, the algorithm may explore many more branches.
Redundant Exploration of Empty Sides
When backtracking, if placing a matchstick on an empty side fails, there is no need to try other empty sides since they are equivalent. Breaking out of the loop when sides[i] == 0 after backtracking prevents exploring symmetric, redundant configurations.
Integer Overflow in Bitmask DP
When using bitmask DP, ensure the DP array size (1 << n) does not cause integer overflow. For n up to 15, this creates arrays of size 32768, which is manageable, but larger values can cause memory issues.