You are given an integer array matchsticks
where matchsticks[i]
is the length of the ith
matchstick. You want 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.
Example 1:
Input: matchsticks = [1,1,2,2,2] Output: true Explanation: You can form a square with length 2, one side of the square came two sticks with length 1.
Example 2:
Input: matchsticks = [3,3,3,3,4] Output: false Explanation: You cannot find a way to form a square with all the matchsticks.
Constraints:
1 <= matchsticks.length <= 15
1 <= matchsticks[i] <= 108
This problem asks whether we can form a square using all the given matchsticks without breaking any of them. Each matchstick must be used exactly once.
This approach uses backtracking to explore all possible combinations of assigning matchsticks to the four sides of the square.
Algorithm:
Preprocessing:
s
).false
.x = s / 4
).x
. If so, it's impossible to form a square, so return false
.Backtracking (DFS):
dfs(u)
: This recursive function explores the possibilities starting from the u
-th matchstick.u
reaches the end of the matchsticks
array, it means all matchsticks have been used, and a square has been formed, so return true
.i
from 0 to 3). Try adding the current matchstick (matchsticks[u]
) to each side.
edges[i]
) after adding the matchstick exceeds x
, the side length constraint is violated, so continue to the next side.dfs(u + 1)
to continue with the next matchstick. If the recursive call returns true
, it means a square can be formed, so return true
.false
, it means this path doesn't lead to a solution, so remove the matchstick from the current side (edges[i] -= matchsticks[u]
) and try another side.false
.Time Complexity: O(4n), where n is the number of matchsticks. In the worst case, we explore all possible ways to assign matchsticks to the four sides. However, the sorting and early pruning significantly reduce the actual runtime.
Space Complexity: O(n) due to the recursion depth in the dfs
function.
This approach uses bit manipulation to represent the states of matchsticks and dynamic programming to optimize the search.
Algorithm:
Preprocessing: Similar to Solution 1, perform the same initial checks (sum, divisibility by 4, max length). Sort the matchsticks
.
Dynamic Programming (Memoization):
dfs(state, t)
: This function uses memoization (@cache
in Python) to store the results of subproblems. state
is a bitmask representing which matchsticks have been used (1 if used, 0 if not). t
is the current total length of matchsticks assigned to one side of the square, modulo s
.state == (1 << len(matchsticks)) - 1
), a solution is found, return True
.dfs
with the updated state
and t
. If the recursive call returns true
, return true
.false
.Time Complexity: O(n * 2n), where n is the number of matchsticks. The state space is 2n, and for each state, we iterate through n matchsticks. The memoization significantly reduces redundant computations.
Space Complexity: O(2n) due to the memoization table.
Code Examples (Python): The code examples provided in the original problem description demonstrate both approaches. The Python code for Solution 2 utilizes the @cache
decorator for memoization, which is a convenient way to implement dynamic programming in Python. Other languages might require explicit memoization using dictionaries or arrays.