Problem
Given an array of words, find two words that share no common letters and return the maximum product of their lengths. If no such pair exists, return 0.
- Input:
words = ["abcw", "baz", "foo", "bar", "xtfn", "abcdef"] - Output:
16 - Explanation:
"abcw"(length 4) and"xtfn"(length 4) share no letters, so 4 ร 4 = 16.
Counter-example: "foo" and "xtfn" both contain 'f', so they cannot be paired.
Intuition
For any pair of words, the only thing that matters is whether their character sets overlap. Since the input contains only lowercase letters, each word's set of 26 possible characters fits exactly into a 26-bit integer โ one bit per letter. Checking overlap then becomes a single bitwise AND instead of scanning characters one by one, and because the masks can be precomputed once, every pair check drops to O(1).
Approach 1 โ Set Comparison
Build a character set for each outer word and scan the inner word's characters to detect overlap.
- For each index
i, convertwords[i]into a character set. - For each index
j > i, check whether any character inwords[j]appears in the set. - If no character overlaps, compute
len(words[i]) ร len(words[j]). - Return the maximum product found across all pairs.
1def maxProduct(words: list[str]) -> int:
2 max_product = 0
3 for i in range(len(words)):
4 char_set = set(words[i])
5 for j in range(i + 1, len(words)):
6 if not any(char in char_set for char in words[j]):
7 max_product = max(max_product, len(words[i]) * len(words[j]))
8 return max_productTime: O(nยฒ ร L) โ for each of the O(nยฒ) pairs, checking overlap costs O(L) in the worst case.
Space: O(n) โ a character set of at most 26 entries per word, so O(n ร 26) = O(n) total.
Approach 2 โ Bitmask Precomputation
Encode each word as a 26-bit integer where bit k is set if the word contains the k-th letter. Two words share no letters if and only if their bitmasks AND to zero, turning the per-pair overlap check from O(L) to O(1).
- For each word, initialize its mask to 0, then OR in
1 << (c - 'a')for every characterc. - Store all masks in an array alongside the words.
- For every pair
(i, j), computemasks[i] & masks[j]. - If the result is 0 (no shared bits), update the maximum product.
1def maxProduct(words: list[str]) -> int:
2 masks = [0] * len(words)
3 for i, word in enumerate(words):
4 for char in word:
5 masks[i] |= 1 << (ord(char) - ord('a'))
6
7 max_product = 0
8 for i in range(len(words)):
9 for j in range(i + 1, len(words)):
10 if masks[i] & masks[j] == 0: # no shared bits means no shared letters
11 max_product = max(max_product, len(words[i]) * len(words[j]))
12 return max_productTime: O(nL + nยฒ) โ O(nL) to precompute all masks once, then O(nยฒ) pair checks each at O(1).
Space: O(n) โ one 32-bit integer mask per word.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Set Comparison | O(nยฒ ร L) | O(n) | When word count is small and character overlap is rarely absent (few zero-AND pairs) |
| Bitmask Precomputation | O(nL + nยฒ) | O(n) | Standard approach โ preprocessing amortizes to O(1) per pair check regardless of word length |
Common Mistakes
- Missing parentheses in Java's overlap check:
masks[i] & masks[j] == 0is silently parsed asmasks[i] & (masks[j] == 0)because==binds tighter than&in Java. The AND comparesmasks[i]against a boolean (0 or 1), not the pair's combined mask, producing wrong results with no compile error. - Using the character index instead of a shifted bit: Writing
masks[i] |= (c - 'a')sets bits 0โ25 as raw values rather than positions โ'b'would set bit 1 (value 1), but so would'a' + 1and many other things. The correct expression is1 << (c - 'a'). - Starting the inner loop at
j = 0instead ofj = i + 1: This double-counts every pair and includes self-pairs(i, i), where the mask ANDs with itself (non-zero for any non-empty word) but the length product may still be compared. It also doubles runtime for no benefit. - Unsigned multiplication overflow in C++:
words[i].size() * words[j].size()returnssize_t(unsigned). For long words the product can silently wrap, comparing as a huge number against the signedmaxProduct. Cast at least one operand tointorlong longbefore multiplying. - Stopping at the first non-overlapping pair: The problem requires the maximum product across all valid pairs โ there may be several zero-AND pairs and the first found is rarely the largest.
Related Problems
single-numberโ introductory XOR/bit-manipulation problem that builds the bitwise-operator intuition used herecounting-bitsโ reasoning about which bits are set in integers across a rangenumber-of-1-bitsโ counting set bits (popcount), a natural companion to building bitmasksbitwise-and-of-numbers-rangeโ bit masking applied across a numeric range rather than character setsfind-all-duplicates-in-an-arrayโ uses bit-level bookkeeping to track element membership, the same idea as the character-presence mask here