↓Skip to main content
  1. LeetCode/

LeetCode 473: Matchsticks to Square

·2 mins· ·
LeetCode Medium Array Dynamic-Programming Backtracking Bit-Manipulation
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: medium First Attempt: 2022-11-16

  • Submissions: Time Limit Exceeded → Accepted ×2 → Runtime Error ×3 → Time Limit Exceeded → Accepted ×2

Approach
#

Placement backtracking (Backtracking template): each stick goes into one of four sides of length total / 4. Pruning matters:

  • If the total is not divisible by 4, or the longest stick exceeds a side, return False.
  • Sort longest first: big sticks fail fast.
  • Skip a side the stick would overflow.
  • If this side’s current length equals a side already tried, the outcome is the same, so skip.

My Attempts
#

This took 9 submissions:

  • Attempt 1 was correct four-side backtracking but had no memoization or equal-side pruning, and timed out.
  • The @cache version first had misspelled names (value, e5, NameError). After that the four branches were summed with +, forcing every branch to finish before adding, and it timed out again; one run happened to finish in time and was accepted (it returned an integer, nonzero counting as True).
  • A 2022-11-27 rewrite with or and longest-first sorting passed reliably.

Solution
#

class Solution:
    def makesquare(self, matchsticks: List[int]) -> bool:
        total = sum(matchsticks)
        if total % 4:
            return False
        side = total // 4
        matchsticks.sort(reverse=True)
        if matchsticks[0] > side:
            return False
        sides = [0] * 4
        def dfs(i):
            if i == len(matchsticks):
                return True
            tried = set()
            for k in range(4):
                if sides[k] + matchsticks[i] > side or sides[k] in tried:
                    continue
                tried.add(sides[k])
                sides[k] += matchsticks[i]
                if dfs(i + 1):
                    return True
                sides[k] -= matchsticks[i]
            return False
        return dfs(0)

Complexity
#

Worst case O(4^n), passing thanks to pruning; space O(n).

Mistakes to Avoid
#

  • Combine the four branches with or and return early; + explores every branch.
  • Sort longest first; placing small sticks first discovers failures very deep.
  • Sides of equal current length need only one try.

Interview Explanation
#

The total must divide by 4, giving the side length. I sort sticks longest first and backtrack placing each into one of four sides, skipping overflows and sides whose current length was already tried since they behave identically. Exponential in the worst case, but fast with pruning.

Related

LeetCode 78: Subsets
·1 min
LeetCode Medium Array Backtracking Bit-Manipulation
LeetCode 78 note: each element is either taken or not; iteratively, each new number copies every existing subset with the number appended
LeetCode 90: Subsets II
·2 mins
LeetCode Medium Array Backtracking Bit-Manipulation
LeetCode 90 note: sort first; for a number equal to the previous one, extend only the subsets created in the previous step
LeetCode 313: Super Ugly Number
·2 mins
LeetCode Medium Array Math Dynamic-Programming
LeetCode 313 note: generalizing LC 264 with one pointer per prime; with a heap, avoid pushing the same number many times
LeetCode 396: Rotate Function
·2 mins
LeetCode Medium Array Math Dynamic-Programming
LeetCode 396 note: F(k) and F(k - 1) differ by one formula: F(k) = F(k - 1) + sum - n × the element moved to the front
LeetCode 397: Integer Replacement
·2 mins
LeetCode Medium Dynamic-Programming Greedy Bit-Manipulation Memoization
LeetCode 397 note: even numbers are always halved; for odd numbers try +1 and -1 with memoized recursion, since n is too large for an n-sized array
LeetCode 435: Non-overlapping Intervals
·2 mins
LeetCode Medium Array Dynamic-Programming Greedy Sorting
LeetCode 435 note: minimum removals = total minus the maximum kept; sort by right end and greedily keep the one ending earliest