You are given a 0-indexed array of unique strings words
.
A palindrome pair is a pair of integers (i, j)
such that:
0 <= i, j < words.length
,i != j
, andwords[i] + words[j]
(the concatenation of the two strings) is a palindrome.Return an array of all the palindrome pairs of words
.
You must write an algorithm with O(sum of words[i].length) runtime complexity.
For example:
words = ["abcd","dcba","lls","s","sssll"]
should return [[0,1],[1,0],[3,2],[2,4]]
because the palindromes are ["abcddcba","dcbaabcd","slls","llssssll"]
words = ["bat","tab","cat"]
should return [[0,1],[1,0]]
because the palindromes are ["battab","tabbat"]
words = ["a",""]
should return [[0,1],[1,0]]
because the palindromes are ["a","a"]
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The goal is to find pairs of words that, when combined, form a palindrome (reads the same forwards and backward). The brute force method explores every possible combination of words to see if they create a palindrome when joined together.
Here's how the algorithm would work step-by-step:
def palindrome_pairs_brute_force(words):
result = []
for first_word_index in range(len(words)):
for second_word_index in range(len(words)):
# Avoid comparing a word with itself
if first_word_index == second_word_index:
continue
combined_word = words[first_word_index] + words[second_word_index]
# Check if the combined word is a palindrome
if combined_word == combined_word[::-1]:
result.append([first_word_index, second_word_index])
return result
The problem is to find pairs of words that when combined, form a palindrome. Instead of checking every possible combination of words, we can be much more efficient. The key is to use a data structure that helps us quickly find potential palindrome matches by looking at reversed versions of the words.
Here's how the algorithm would work step-by-step:
def palindrome_pairs(words):
word_to_index = {word: index for index, word in enumerate(words)}
results = []
for index, word in enumerate(words):
for j in range(len(word) + 1):
# Consider cases where word is on the left.
prefix = word[:j]
suffix = word[j:]
if is_palindrome(prefix):
reversed_suffix = suffix[::-1]
if reversed_suffix in word_to_index and word_to_index[reversed_suffix] != index:
results.append((word_to_index[reversed_suffix], index))
# Consider cases where word is on the right.
prefix = word[:j]
suffix = word[j:]
if is_palindrome(suffix) and suffix != "":
reversed_prefix = prefix[::-1]
# To avoid duplicates, check non-empty suffix
if reversed_prefix in word_to_index and word_to_index[reversed_prefix] != index:
results.append((index, word_to_index[reversed_prefix]))
return results
def is_palindrome(word):
left = 0
right = len(word) - 1
# Check if a given string is a palindrome.
while left < right:
if word[left] != word[right]:
return False
left += 1
right -= 1
return True
Case | How to Handle |
---|---|
Input array is null or empty | Return an empty list to indicate no palindrome pairs can be formed. |
Array contains an empty string | The empty string can form a palindrome pair with any palindrome string in the array; must check all other strings against the empty string. |
Array contains only one string | Return an empty list, since a pair requires at least two strings. |
Two identical strings in the array | The identical strings form a palindrome pair (string1 + string2, string2 + string1). |
Maximum string length or large number of strings leading to timeout | Optimize the palindrome check to avoid redundant computations, possibly using dynamic programming or a precomputed table. |
Strings that are palindromes themselves | These strings will form pairs with an empty string (if present) or their own reverse. |
Strings with very long common prefixes or suffixes | Consider optimizations like using a Trie data structure to efficiently search for prefixes/suffixes that form palindromes. |
Input array contains very long strings that could lead to memory issues | Implement a streaming approach or limit the length of strings processed to stay within memory constraints. |