Lesson 140 of 250
473. Matchsticks to Square
NeetCode: Matchsticks to Square · LeetCode: 473. Matchsticks to Square · Difficulty: Medium
You are given an array matchsticks where matchsticks[i] is the length of the i-th stick. Use every stick exactly once, without breaking any, to form a square. Return true if you can.
Example
Input: matchsticks = [1,1,2,2,2] Output: true // side length 2: (2), (2), (2), (1,1)
Input: matchsticks = [3,3,3,3,4] Output: falseThis is Partition to K Equal Sum Subsets with k = 4. Both solutions reject early when the total is not divisible by 4 or when a stick is longer than a side. The total is an int. It wraps silently on overflow, so inputs with very large sticks would need long.
Brute force: assign each stick to one of four sides
public class Main {
static class Solution {
public boolean makesquare(int[] matchsticks) {
int total = 0;
for (int x : matchsticks) {
total += x;
}
if (total % 4 != 0) {
return false;
}
int sideLen = total / 4;
for (int x : matchsticks) {
if (x > sideLen) {
return false;
}
}
return place(matchsticks, 0, new int[4], sideLen);
}
private boolean place(int[] sticks, int i, int[] sides, int sideLen) {
if (i == sticks.length) {
for (int s : sides) {
if (s != sideLen) {
return false;
}
}
return true;
}
for (int s = 0; s < 4; s++) {
if (sides[s] + sticks[i] <= sideLen) {
sides[s] += sticks[i];
if (place(sticks, i + 1, sides, sideLen)) {
return true;
}
sides[s] -= sticks[i];
}
}
return false;
}
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.makesquare(new int[] {1, 1, 2, 2, 2}));
System.out.println(sol.makesquare(new int[] {3, 3, 3, 3, 4}));
System.out.println(sol.makesquare(new int[] {5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3}));
}
}true
false
trueEach stick has up to 4 choices, and symmetric arrangements are explored repeatedly. Time: O(4^n). Space: O(n).
Optimal: bitmask DP over the set of used sticks
Fill one side at a time. For a set mask of used sticks, sum(mask) % sideLen is the length of the side in progress, so it depends only on mask. The array filled holds -1 for a mask that is not reachable, in place of an optional value. A mask is reachable if some stick can be added to a reachable smaller mask without overshooting the side. The answer is whether the mask containing all sticks is reachable.
import java.util.Arrays;
public class Main {
static class Solution {
public boolean makesquare(int[] matchsticks) {
int n = matchsticks.length;
int total = 0;
for (int x : matchsticks) {
total += x;
}
if (total % 4 != 0) {
return false;
}
int sideLen = total / 4;
for (int x : matchsticks) {
if (x > sideLen) {
return false;
}
}
int full = (1 << n) - 1;
// filled[mask] = length of the side in progress if mask is reachable, -1 otherwise
int[] filled = new int[full + 1];
Arrays.fill(filled, -1);
filled[0] = 0;
for (int mask = 0; mask <= full; mask++) {
int cur = filled[mask];
if (cur < 0) {
continue;
}
for (int i = 0; i < n; i++) {
if ((mask >> i & 1) == 1 || cur + matchsticks[i] > sideLen) {
continue;
}
filled[mask | (1 << i)] = (cur + matchsticks[i]) % sideLen;
}
}
return filled[full] >= 0;
}
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.makesquare(new int[] {1, 1, 2, 2, 2}));
System.out.println(sol.makesquare(new int[] {3, 3, 3, 3, 4}));
System.out.println(sol.makesquare(new int[] {5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3}));
}
}true
false
trueTime: O(n * 2^n). Space: O(2^n). The problem limits n to 15, so this is about half a million steps.
