给定一个不含重复单词的列表,编写一个程序,返回给定单词列表中所有的连接词。
连接词的定义为:一个字符串完全是由至少两个给定数组中的单词组成的。
示例:
输入: ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"]
输出: ["catsdogcats","dogcatsdog","ratcatdogcat"]
解释: "catsdogcats"由"cats", "dog" 和 "cats"组成;
"dogcatsdog"由"dog", "cats"和"dog"组成;
"ratcatdogcat"由"rat", "cat", "dog"和"cat"组成。
说明:
给定数组的元素总数不超过 10000。
给定数组中元素的长度总和不超过 600000。
所有输入字符串只包含小写字母。
不需要考虑答案输出的顺序。
思路:
方法一:暴力,,开了一个list,用来存储上一次能匹配到的所有位置。然后我们通过暴力遍历可以判断出当前位置能否匹配到。
class Solution {
public List<String> findAllConcatenatedWordsInADict(String[] words) {
Map<String,Boolean> map=new HashMap<>();
List<String> ans=new ArrayList<>();
List<Integer> list=new ArrayList<>();
for(int i=0;i<words.length;i++)
map.put(words[i], true);
for(int i=0;i<words.length;i++) {
list.clear();
for(int j=0;j<words[i].length();j++) {
for(int k=0;k<list.size();k++) {
if(map.containsKey(words[i].substring(list.get(k)+1, j+1))) {
list.add(j);
break;
}
}
if(j<words[i].length()-1 && map.containsKey(words[i].substring(0, j+1)) && !list.contains(j))
list.add(j);
}
if(list.size()>0 && list.get(list.size()-1)==words[i].length()-1)
ans.add(words[i]);
}
return ans;
}
}
方法二:优雅的暴力,set+爆搜
class Solution {
private Set<String> st=new HashSet<>();
public List<String> findAllConcatenatedWordsInADict(String[] words) {
st.addAll(Arrays.asList(words));
List<String> ans=new ArrayList<>(words.length);
for(String word : words) {
if(dfs(word,0,0))
ans.add(word);
}
return ans;
}
private boolean dfs(String word,int idx,int cnt) {
if(idx==word.length()) return cnt>1;
for(int i=idx;i<word.length();i++)
if(st.contains(word.substring(idx, i+1))) {
if(dfs(word,i+1,cnt+1))
return true;
}
return false;
}
}
方法三:前缀树(字典树)
class Solution {
class Trie{
private TreeNode root;
class TreeNode{
String val;
TreeNode[] children;
public TreeNode() {
this.val=null;
this.children=new TreeNode[26];
}
}
Trie() {
this.root=new TreeNode();
}
private void insert(String word) {
TreeNode cur=root;
for(int i=0;i<word.length();i++) {
int c=word.charAt(i)-'a';
if(cur.children[c]==null)
cur.children[c]=new TreeNode();
cur=cur.children[c];
}
cur.val=word;
}
private boolean search(String word,int idx) {
TreeNode cur=root;
for(int i=idx;i<word.length();i++) {
int c=word.charAt(i)-'a';
cur=cur.children[c];
if(cur==null)
return false;
if(i<word.length()-1) {
if(cur.val!=null && !word.equals(cur.val)) {
if(search(word,i+1))
return true;
}
}
}
return cur.val!=null && !word.equals(cur.val);
}
}
public List<String> findAllConcatenatedWordsInADict(String[] words) {
Trie trie=new Trie();
for(String word : words)
trie.insert(word);
List<String> ans=new ArrayList<>(words.length);
for(String word : words)
if(trie.search(word,0))
ans.add(word);
return ans;
}
}