472 Concatenated Words
题目链接:472 Concatenated Words
题意
给定一个字符串数组(vector),要求找出当中所有能被数组中其他多于一个字符串组成的字符串
解法
- 构建字典树,每个字符串对应字典树中的一条路径,这条路径不必以叶子节点结尾,因为不同字符串可能共享一条路径的一部分,比如“cat”和“cats”,所以在字典树节点类中增加一个bool字段isEnd。
要查询一个字符串是否可以由字典树中的多个字符串拼接而成,用一个下标current指向字符串当前的字符,用计数器count记录目前子串可以拆分成多少个字符串,查询每次都从树的根节点开始
- 如果当前节点没有current指向的字符对应的子节点,返回false
- 如果有对应的子节点,判断该节点是否是一条路径的终点,即判断该节点的isEnd字段
- 如果isEnd为假,只需将当前节点迭代为该子节点,并且下标current自增
- 如果isEnd为真,首先判断current是否已经到达字符串末尾
- 如果是,返回计数器是否大于0的结果
- 否则,面临两个选择,一是沿着这条路径访问下个节点,二是重新从根节点开始访问,这两种情况都有可能,比如字典中已经有cat,dog,catdog,如果要查询catdogcat,则对应第一种情况,如果要查询catdog,则对应第二种情况,所以这里使用深度优先搜索试着迭代一次,如果成功直接返回true,否则沿着当前路径继续搜索。
总体步骤如下:
- 将所有字符串添加到字典树中
- 再次遍历数组中所有字符串,对于每个字符串,查询是否可以由字典树中多个字符串拼接而成
代码
#include<iostream>
#include<vector>
#include<string>
#include<map>
using namespace std;
class DictNode {
public:
bool isEnd;
map<char, DictNode*> next;
DictNode() {
isEnd = false;
}
};
class Solution {
public:
DictNode *root;
vector<string> findAllConcatenatedWordsInADict(vector<string>& words) {
vector<string> result;
root = new DictNode();
for (string word : words)
add(word);
for (string word : words) {
if (canResolve(word, 0, 0)) {
result.push_back(word);
}
}
return result;
}
void add(string word) {//为word在字典树中构建一条路径
DictNode *node = root;
for (int current = 0; current < word.length(); ++current) {
if (node->next.find(word[current] ) == node->next.end())
node->next[word[current]] = new DictNode();
node = node->next[word[current]];
}
node->isEnd = true;//标出字符串路径终点
}
bool canResolve(string word, int current, int count) {
if (word == "catsdogcats")
int r = 0;
DictNode *node = root;
for (int i = current; i < word.length(); ++i) {
if (node->next.find(word[i])==node->next.end())
return false;
if (node->next[word[i]]->isEnd) {
if (i == word.length() - 1) {
return count >= 1;
}
if (canResolve(word, i + 1, count + 1)) {//深度优先搜索迭代判断
return true;
}
}
node = node->next[word[i]];
}
return false;
}
};
算法复杂度
算法复杂度为O(nm)。n为数组长度,m为数组中字符串平均长度。
注意
字典树节点表示子节点的数据结构如果简单地选择节点指针数组,那么在面对比如a,aa,aaa,aaaa…这种字典树退化成链表的情况可能会出现超出内存限制的问题,所以最好方便点办法是使用map存储子节点指针。