Given an array of strings words (without duplicates), return all the concatenated words in the given list of words.
A concatenated word is defined as a string that is comprised entirely of at least two shorter words in the given array.
Example 1:
Input: words = [“cat”,“cats”,“catsdogcats”,“dog”,“dogcatsdog”,“hippopotamuses”,“rat”,“ratcatdogcat”]
Output: [“catsdogcats”,“dogcatsdog”,“ratcatdogcat”]
Explanation: “catsdogcats” can be concatenated by “cats”, “dog” and “cats”;
“dogcatsdog” can be concatenated by “dog”, “cats” and “dog”;
“ratcatdogcat” can be concatenated by “rat”, “cat”, “dog” and “cat”.
Example 2:
Input: words = [“cat”,“dog”,“catdog”]
Output: [“catdog”]
Constraints:
- 1 <= words.length <= 104
- 1 <= words[i].length <= 30
- words[i] consists of only lowercase English letters.
- All the strings of words are unique.
- 1 <= sum(words[i].length) <= 105
假设 dp[word]为 word 是否可以拆分为 2 个以上的 words 内包含的单词,对于任意一个 word, 用 i(0 <= i < word.len), 将其分为 2 部分, word[…=i], word[i+1…], 如果 word[i+1…]在 words 中存在且 dp[word[…=i]] == true, 则 word 是由 2 个及以上的 words 中的单词组成的。
use std::collections::{HashMap, HashSet};
impl Solution {
fn dp(words: &HashSet<String>, mut word: String, cache: &mut HashMap<String, bool>) -> bool {
if let Some(&c) = cache.get(&word) {
return c;
}
let mut second_half = String::new();
while word.len() > 1 {
let c = word.pop().unwrap();
second_half.insert(0, c);
if words.contains(&second_half) {
if words.contains(&word) {
cache.insert(format!("{}{}", word, second_half), true);
return true;
}
if Solution::dp(words, word.clone(), cache) {
cache.insert(format!("{}{}", word, second_half), true);
return true;
}
}
}
cache.insert(format!("{}{}", word, second_half), false);
false
}
pub fn find_all_concatenated_words_in_a_dict(words: Vec<String>) -> Vec<String> {
let set: HashSet<String> = words.iter().map(|w| w.to_owned()).collect();
let mut ans = Vec::new();
for w in words {
if Solution::dp(&set, w.clone(), &mut HashMap::new()) {
ans.push(w);
}
}
ans
}
}