You are given a list of synonymous words synonyms
where synonyms[i] = [wordi, synonymi]
. A sentence can be transformed by replacing some of its words with synonyms.
For example, "happy boy"
can be transformed into "joyful boy"
, "happy man"
, or "joyful man"
.
Given a sentence text
and a list of synonymous words synonyms
, construct all possible synonymous sentences sorted lexicographically.
Example 1:
Input: synonyms = [["happy","joy"]], text = "I am happy today but was sad yesterday"
Output: ["I am happy today but was sad yesterday","I am joy today but was sad yesterday"]
Example 2:
Input: synonyms = [["happy","joy"],["strong","healthy"]], text = "I am happy and strong today but was sad yesterday"
Output: ["I am happy and healthy today but was sad yesterday","I am happy and strong today but was sad yesterday","I am joy and healthy today but was sad yesterday","I am joy and strong today but was sad yesterday"]
Example 3:
Input: synonyms = [["happy","joy"],["strong","healthy"],["sad","melancholy"],["sad","dejected"]], text = "I am happy and strong today but was sad yesterday"
Output: ["I am happy and healthy today but was dejected yesterday","I am happy and healthy today but was melancholy yesterday","I am happy and healthy today but was sad yesterday","I am happy and strong today but was dejected yesterday","I am happy and strong today but was melancholy yesterday","I am happy and strong today but was sad yesterday","I am joy and healthy today but was dejected yesterday","I am joy and healthy today but was melancholy yesterday","I am joy and healthy today but was sad yesterday","I am joy and strong today but was dejected yesterday","I am joy and strong today but was melancholy yesterday","I am joy and strong today but was sad yesterday"]
Constraints:
0 <= synonyms.length <= 10
synonyms[i].length == 2
1 <= wordi.length <= 10
1 <= synonymi.length <= 10
wordi != synonymi
1 <= text.length <= 105
text
consists of lower-case English letters and spaces only.text
.text
are separated by a single space.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 brute force approach generates every possible sentence that's synonymous to the original sentence. It achieves this by systematically replacing each word in the original sentence with all its synonyms and checking if the resulting sentence is valid. It's like exploring every single path to see if it leads to a correct solution.
Here's how the algorithm would work step-by-step:
def generate_synonymous_sentences_brute_force(synonyms, text):
synonym_map = {}
for synonym_pair in synonyms:
word1, word2 = synonym_pair
if word1 not in synonym_map:
synonym_map[word1] = {word1}
if word2 not in synonym_map:
synonym_map[word2] = {word2}
synonym_map[word1].add(word2)
synonym_map[word2].add(word1)
unique_sentences = set()
def generate_sentences(current_sentence_words, index):
# Base case: If we've processed all words, add the sentence
if index == len(current_sentence_words):
unique_sentences.add(" ".join(current_sentence_words))
return
word = current_sentence_words[index]
# If the word has synonyms, explore each synonym
if word in synonym_map:
for synonym in synonym_map[word]:
new_sentence_words = current_sentence_words[:]
new_sentence_words[index] = synonym
generate_sentences(new_sentence_words, index + 1)
# Always explore the original word as well
generate_sentences(current_sentence_words, index + 1)
generate_sentences(text.split(), 0)
# Convert to a sorted list for the expected output
return sorted(list(unique_sentences))
The goal is to create all possible sentences by replacing words with their synonyms. We can represent the synonym relationships and use them to explore all valid combinations systematically, avoiding redundant computations by remembering which combinations have already been tried.
Here's how the algorithm would work step-by-step:
def generate_synonymous_sentences(synonyms, sentence):
word_groups = {}
for synonym_pair in synonyms:
word1, word2 = synonym_pair
group1 = word_groups.get(word1, {word1})
group2 = word_groups.get(word2, {word2})
unified_group = group1.union(group2)
for word in unified_group:
word_groups[word] = unified_group
words_in_sentence = sentence.split()
synonymous_sets = []
for word in words_in_sentence:
synonymous_sets.append(word_groups.get(word, {word}))
sentences = set()
def backtrack(index, current_sentence):
# Base case: sentence complete.
if index == len(synonymous_sets):
sentences.add(" ".join(current_sentence))
return
# For each synonym, extend the sentence.
for synonym in synonymous_sets[index]:
backtrack(index + 1, current_sentence + [synonym])
# Initiate the backtracking algorithm.
backtrack(0, [])
# Convert the set to a sorted list
return sorted(list(sentences))
Case | How to Handle |
---|---|
synonyms is null or empty | Return a list containing just the input text since no synonyms exist. |
text is null or empty | Return an empty list since there's no text to process. |
synonyms contain duplicate pairs | Treat duplicate synonym pairs as the same relationship and proceed normally; the algorithm should handle redundancy. |
synonyms contain contradictory pairs (e.g., a <-> b and a <-> c where b and c are not synonyms) | The algorithm should construct transitive synonym relationships; no contradiction handling is explicitly needed, but the output might be unexpected if input is nonsensical. |
Very long input text exceeding memory limitations | Consider streaming or divide-and-conquer approaches to process the text in chunks if memory becomes a bottleneck. |
Synonym pairs create a cycle (e.g., a<->b, b<->c, c<->a) | The algorithm's union-find structure will correctly handle cycles without infinite loops. |
Text contains words not present in the synonym pairs | Treat these words as themselves and include them in the generated sentences, leaving them untouched. |
Maximum number of synonyms, potentially causing stack overflow in recursive approaches | Use iterative approaches like Breadth-First Search to avoid potential stack overflow issues. |