1258. Synonymous Sentences
Given a list of pairs of equivalent words synonyms
and a sentence text
, Return all possible synonymous sentences sorted lexicographically.
Example 1:
Input:
synonyms = [["happy","joy"],["sad","sorrow"],["joy","cheerful"]],
text = "I am happy today but was sad yesterday"
Output:
["I am cheerful today but was sad yesterday",
"I am cheerful today but was sorrow yesterday",
"I am happy today but was sad yesterday",
"I am happy today but was sorrow yesterday",
"I am joy today but was sad yesterday",
"I am joy today but was sorrow yesterday"]
Constraints:
0 <= synonyms.length <= 10
synonyms[i].length == 2
synonyms[0] != synonyms[1]
All words consist of at most
10
English letters only.text
is a single space separated sentence of at most10
words.
// Find with path compression
string findRoot(unordered_map<string, string>& roots, const string& s) {
return roots[s] == s ? s : roots[s] = findRoot(roots, roots[s]);
}
void dfs(unordered_map<string, string>& roots, unordered_set<string>& words, int start, string& text, vector<string>& res) {
if (start >= text.length()) { // actually there is no equality case in this code
res.emplace_back(text);
return;
}
string cur; // current word
int idx;
for (idx = start; idx < text.length() && text[idx] != ' '; ++idx) {
cur += text[idx];
}
++idx; // skip whitespace
// Keep the current word unchanged
dfs(roots, words, idx, text, res);
string pre = text;
// Change the current word with its synonyms
if (roots.count(cur)) {
for (const string& word : words) {
if (cur != word && findRoot(roots, cur) == findRoot(roots, word)) {
text.replace(start, cur.length(), word);
dfs(roots, words, idx - cur.length() + word.length(), text, res);
text = pre; // reset to the previous state before replacement
}
}
}
}
// Union Find + DFS
vector<string> generateSentences(vector<vector<string>>& synonyms, string text) {
unordered_map<string, string> roots;
unordered_map<string, int> root_sz;
unordered_set<string> words;
// Union
for (const vector<string>& syn : synonyms) {
if (!roots.count(syn[0])) {
roots[syn[0]] = syn[0];
root_sz[syn[0]] = 1;
}
if (!roots.count(syn[1])) {
roots[syn[1]] = syn[1];
root_sz[syn[1]] = 1;
}
words.insert(syn[0]);
words.insert(syn[1]);
string r1 = findRoot(roots, syn[0]), r2 = findRoot(roots, syn[1]);
if (r1 != r2) {
if (root_sz[r1] >= root_sz[r2]) roots[r2] = r1;
else roots[r1] = r2;
}
}
vector<string> res;
// Backtracking
dfs(roots, words, 0, text, res);
// Sort lexicographically
sort(res.begin(), res.end());
return res;
}
// Find with path compression
string getRoot(unordered_map<string, string>& roots, const string& s) {
return roots[s] == s ? s : roots[s] = getRoot(roots, roots[s]);
}
vector<string> dfs(unordered_map<string, string>& roots, unordered_map<string, vector<string> >& unioned_synonyms, const vector<string>& words, int pos) {
if (pos == words.size()) return {""};
vector<string> right_res = dfs(roots, unioned_synonyms, words, pos + 1);
vector<string> res;
for (string& s : right_res) {
if (!s.empty()) s = " " + s;
if (roots.count(words[pos])) {
string root = getRoot(roots, words[pos]);
for (const string& syn : unioned_synonyms[root]) {
res.emplace_back(syn + s);
}
} else {
res.emplace_back(words[pos] + s);
}
}
return res;
}
// Union Find + DFS
vector<string> generateSentences(vector<vector<string>>& synonyms, string text) {
unordered_map<string, string> roots;
for (const vector<string>& p : synonyms) {
string u = p[0], v = p[1];
if (!roots.count(u)) roots[u] = u;
if (!roots.count(v)) roots[v] = v;
string r1 = getRoot(roots, u), r2 = getRoot(roots, v);
if (r1 != r2) roots[r2] = r1;
}
unordered_map<string, vector<string> > unioned_synonyms;
for (auto& entry : roots) {
string root = getRoot(roots, entry.first);
unioned_synonyms[root].emplace_back(entry.first);
}
vector<string> words;
istringstream iss(text);
string word;
while (iss >> word) words.emplace_back(word);
vector<string> res = dfs(roots, unioned_synonyms, words, 0);
sort(res.begin(), res.end());
return res;
}
// Find with path compression
string getRoot(unordered_map<string, string>& roots, const string& s) {
return roots[s] == s ? s : roots[s] = getRoot(roots, roots[s]);
}
vector<string> dfs(unordered_map<string, string>& roots, const vector<string>& words, int pos) {
if (pos == words.size()) return {""};
vector<string> right_res = dfs(roots, words, pos + 1);
vector<string> res;
for (string& s : right_res) {
if (!s.empty()) s = " " + s;
if (roots.count(words[pos])) {
string root = getRoot(roots, words[pos]);
for (auto& e : roots) {
if (getRoot(roots, e.first) == root) {
res.emplace_back(e.first + s);
}
}
} else {
res.emplace_back(words[pos] + s);
}
}
return res;
}
// Union Find + DFS
vector<string> generateSentences(vector<vector<string>>& synonyms, string text) {
unordered_map<string, string> roots;
for (const vector<string>& p : synonyms) {
string u = p[0], v = p[1];
if (!roots.count(u)) roots[u] = u;
if (!roots.count(v)) roots[v] = v;
string r1 = getRoot(roots, u), r2 = getRoot(roots, v);
if (r1 != r2) roots[r2] = r1;
}
vector<string> words;
istringstream iss(text);
string word;
while (iss >> word) words.emplace_back(word);
vector<string> res = dfs(roots, words, 0);
sort(res.begin(), res.end());
return res;
}
Last updated
Was this helpful?