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.
这种字符串处理的题我还是没有思路。用动态规划处理连接词这种题还是没有思路。
dp[i]表示前i个字符是不是连接词,如果前i个不是的话,后面的也不用判断了。如果前i个是就判断从第i个字符开始,依次判断【i,j】子字符串是否是字典中的词。如果是则将dp[j+1]=true。
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
复杂度是O(n^3)
因为查找子字符串是否是字典中的词最多也需要O(n)所以总的时间复杂度是O(N^4)。
可以引入一种数据结构叫trie树,这是一种26叉树,可以在常数时间内找到字符串,对于字符串s[n],指针之前已经定位在了s[n-1]所以对于s[n]只要在常数时间就能查找到。所以可以将时间复杂度降为O(n^3)。
struct TrieNode
{
vector<TrieNode*> children = vector<TrieNode*>(26,NULL);
bool isterm = false;
};
class Solution {
public:
vector<string> findAllConcatenatedWordsInADict(vector<string>& words)
{
int n = words.size();
vector<string> ans;
TrieNode* root = new TrieNode;
for(int i=0;i<n;i++)
{
addtree(root,words[i]);
}
for(int i=0;i<n;i++)
{
if(isconcat(words[i],root)) {
ans.push_back(words[i]);
}
}
return ans;
}
TrieNode* addtree(TrieNode* r,string w)
{
int n = w.size();
if(n == 0) {
return r;
}
for(int i = 0; i<n; ++i)
{
if(!r->children[w[i]-'a'])
{
r->children[w[i]-'a'] = new TrieNode;
}
r = r->children[w[i]-'a'];
}
r->isterm = true;
return r;
}
bool isconcat(string &s,TrieNode* q)
{
int n = s.size();
if(n==0)
{
return false;
}
vector<bool> dp(n+1,false);
dp[0] = true;
for(int i=0;i<n;i++)
{
if(dp[i]==false) continue;
TrieNode* p = q;
for(int j=i;j<n;j++)
{
if(!p->children[s[j]-'a']) break;
if(i==0&&j==n-1) break;
p = p->children[s[j]-'a'];
if(p->isterm) dp[j+1] = true;
}
if(dp[n]) break;
}
return dp[n];
}
};