Given a list of words (without duplicates), please write a program that returns all 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:
Input: ["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".
刷第二遍时候的代码
public class Solution {
public List<String> findAllConcatenatedWordsInADict(String[] words) {
Set<String> set=new HashSet<String>();
for(String str:words) set.add(str);
// Arrays.sort(words,new Comparator<String>() {//排序是没有意义的
// @Override
// public int compare(String o1, String o2) {
// return o2.length()-o1.length();
// }
// });
List<String> re=new ArrayList<String>();
for(String str:words){
if(isOk(str, set)){
re.add(str);
}
}
return re;
}
//这段代码是dp 题目还可以延伸为传入参数不是一个Set 而是一个HashMap 即对数量有要求 那么我们要在每次dp的时候初始化一个HashMap 保留当前的使用字符串和使用个数
//与总的使用个数做比较 这时使用的是dfs 不是dp 因为这时候的dp的状态集不能用简单的boolean表示 还涉及到使用的字符串的个数
public boolean isOk(String str,Set<String> set){
if(str.length()==0) return false;
set.remove(str);
boolean[] re=new boolean[str.length()+1];
re[0]=true;
for(int i=0;i<str.length();i++){
for(int j=0;j<=i;j++){
re[i+1]=re[j-1+1]&&set.contains(str.substring(j,i+1));
if(re[i+1]) break;
}
}
set.add(str);
return re[re.length-1];
}
}
刷第一遍的时候的代码
public class Solution {
public List<String> findAllConcatenatedWordsInADict(String[] words) {
List<String> re=new ArrayList<String>();
if(words.length==0) return re;
Arrays.sort(words,new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length()-o2.length();
}
});
Set<String> set=new HashSet<String>();
for(int i=0;i<words.length;i++){
if(isOk(words[i],set)){
re.add(words[i]);
}
// else{
// set.add(words[i]);//这样写没有必要 因为hash的查找反正都是o(1),而且测试数据可能是 a, aa, aaa, aaaa, aaaaa .....
// }
set.add(words[i]);
}
return re;
}
//下面这段程序是重点
//动态规划的数组的下标表示的是s字符串的间隙
private boolean isOk(String s, Set<String> set) {
if(set.isEmpty()) return false;
boolean[] re=new boolean[s.length()+1];
re[0]=true;
for(int i=1;i<s.length()+1;i++){
for(int j=0;j<i;j++){
if(re[j]==false) continue;
String str=s.substring(j,i);
if(set.contains(str)){
re[i]=true;
break;
}
}
}
return re[re.length-1];
}
}