问题描述:
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”.
Note:
- The number of elements of the given array will not exceed
10,000
- The length sum of elements in the given array will not exceed
600,000
. - All the input string will only include lower case letters.
- The returned elements order does not matter.
问题分析:
题意是找出所有可以由至少2个单词拼接而成的单词,可以一个一个的进行判断,即Word Break题。
而判断某个单词是否可以被其他单词拼接而成,可以按字符向后判断,判断从0到当前第i个字符是否可以拼接,如果前面从0到第j个字符可以拼接,同时word(j,i)也是一个单词,则从0到第i个字符可以拼接。
转移方程:
dp[i]=(dp[j]&&word(j,i)),j<,i
代码如下:
public List<String> findAllConcatenatedWordsInADict(String[] words) {
List<String> result=new ArrayList<String>();
Set<String> set=new HashSet(Arrays.asList(words));
for(String word: words){
set.remove(word);
if(breakWord(set,word))
result.add(word);
set.add(word);
}
return result;
}
public Boolean breakWord(Set<String> set, String word){
if(word==null||word.length()==0)
return false;
int n=word.length();
boolean[]dp=new boolean[n+1];
dp[0]=true;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
if(dp[j]&&set.contains(word.substring(j,i)))
{
dp[i]=true;
break;
}
}
}
return dp[n];
}