You are given a string array words, consisting of distinct 4-letter strings, each containing lowercase English letters.
A word square consists of 4 distinct words: top, left, right and bottom, arranged as follows:
top forms the top row.bottom forms the bottom row.left forms the left column (top to bottom).right forms the right column (top to bottom).It must satisfy:
top[0] == left[0], top[3] == right[0]bottom[0] == left[3], bottom[3] == right[3]Return all valid distinct word squares, sorted in ascending lexicographic order by the 4-tuple (top, left, right, bottom).
Example 1:
Input: words = ["able","area","echo","also"]
Output: [["able","area","echo","also"],["area","able","also","echo"]]
Explanation:
There are exactly two valid 4-word squares that satisfy all corner constraints:
"able" (top), "area" (left), "echo" (right), "also" (bottom)
top[0] == left[0] == 'a'top[3] == right[0] == 'e'bottom[0] == left[3] == 'a'bottom[3] == right[3] == 'o'"area" (top), "able" (left), "also" (right), "echo" (bottom)
Thus, the answer is [["able","area","echo","also"],["area","able","also","echo"]].
Example 2:
Input: words = ["code","cafe","eden","edge"]
Output: []
Explanation:
No combination of four words satisfies all four corner constraints. Thus, the answer is empty array [].
Constraints:
4 <= words.length <= 15words[i].length == 4words[i] consists of only lowercase English letters.words[i] are distinct.Problem Overview: You are given a list of words where each word has the same length. The task is to construct all possible word squares. A word square is a sequence of words such that the kth row and kth column read the same string. For example, the first word defines the first column, the second word must match the second column prefix, and so on.
Approach 1: Brute Force Enumeration (O(N! * L^2) time, O(L) space)
The naive idea is to try every possible ordering of words and check whether they form a valid square. Generate permutations using recursion or iterative enumeration, then validate the grid by comparing characters at grid[i][j] and grid[j][i]. Validation takes O(L^2) for word length L. This approach quickly becomes infeasible because permutations grow factorially with the number of words. It is mainly useful for understanding the structural constraint of word squares.
Approach 2: Backtracking with Prefix Hash Map (O(N * L^2 * B) time, O(N * L) space)
A more practical approach builds the square row by row using backtracking. When placing the kth word, the prefix formed by characters square[0][k], square[1][k], ..., square[k-1][k] must match the start of the candidate word. Precompute a prefix lookup table using a hash map where each prefix maps to all words that start with it. During recursion, compute the required prefix and fetch valid candidates in constant time. This prunes most invalid branches early, making the search manageable.
The algorithm iterates through each word as a starting row, then recursively fills the next rows while maintaining the prefix constraint. The prefix map is built by iterating through every word and storing prefixes of length 1..L. The recursion depth is at most L, and each step narrows candidates using prefix filtering. This combines string prefix matching with array style indexing for column validation.
Approach 3: Backtracking with Trie Prefix Search (O(N * L^2 * B) time, O(N * L) space)
Instead of a hash map, store all words in a Trie. Each Trie node tracks the indices of words that share the prefix represented by that node. While building the square, traverse the Trie using the required prefix and immediately retrieve candidate words. This reduces repeated prefix scans and keeps lookup efficient even when the dictionary is large.
Recommended for interviews: Backtracking with prefix lookup (hash map or Trie) is the expected solution. Interviewers want to see that you identify the prefix constraint and prune the search tree early. Starting with the brute-force permutation idea shows you understand the problem structure, but switching to prefix-guided backtracking demonstrates algorithmic optimization and practical search design.
Python
Java
C++
Go
TypeScript
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Brute Force Permutations | O(N! * L^2) | O(L) | Only for very small input sizes or conceptual understanding of word square validation |
| Backtracking + Prefix Hash Map | O(N * L^2 * B) | O(N * L) | General case; fast prefix lookup prunes invalid branches during search |
| Backtracking + Trie | O(N * L^2 * B) | O(N * L) | Best when the dictionary is large and repeated prefix searches are frequent |
LeetCode Weekly Contest 483 | Word Squares II (Q2) | Backtracking Explained in Java • codingX krishna • 479 views views
Watch 7 more video solutions →Practice Word Squares II with our built-in code editor and test cases.
Practice on FleetCode