题目描述:
给出一个按字母序排列的单词列表,找到其中存在的复合词。复合词的定义是由单词列表中其他的两个单词拼接而成。所有单词均为小写。
思路:
如果直接两层遍历所有的单词组合,看他们加在一起是否是单词列表中的一个,在输入如此大的情况下,肯定会超时。我的做法是,定义vector<string> svec[26]
,将单词按首字母分别存放在svec[i]
里,对一个复合词,他的前半部分单词首字母和他相同,先在svec[i]
里找前半部分单词,如果存在那么再去找后半部分单词,根据后半部分单词的首字母容易定位到是在svec[j]
查找。
需注意的细节:输出的复合词不重复出现,故用set
保存答案,同时也完成了按字母序输出的要求。
代码:
"点击查看代码"
#include <iostream> #include <map> #include <string> #include <vector> #include <set> using namespace std;
bool preword(string s1, string s2){ //判断s1是否是s2的前缀
if(s1.size() > s2.size()) return false;
int i = 0;
for(; i < s1.size(); ++i){
if(s1[i] != s2[i]) break;
}
if(i == s1.size()) return true;
else return false;
}int main()
{
string s;
map<string, int> smap;
vectorsvec[26];
string compound;
setans;
while(cin >> s){
svec[s[0]-'a'].push_back(s); //按首字母分别存放
}
for(int i = 0; i < 26; ++i){ //对a~z的每一个首字母
for(int j = 0; j < svec[i].size(); ++j){
for(int k = 0; k < j; ++k){ //因为输入是按字母序输入的,所以svec[i][j]是在svec[i][j]后面的单词
if(preword(svec[i][k], svec[i][j])){ //如果k是j的前缀
string s = svec[i][j].substr(svec[i][k].size(), svec[i][j].size() - svec[i][k].size()); //再考虑后半部分字串
for(int m = 0; m < svec[s[0]-'a'].size(); ++m){ //看后半部分字串是否是svec[s[0]-'a']中的单词
if(s.compare(svec[s[0]-'a'][m]) == 0) ans.insert(svec[i][j]);
}
}
}
}
}
for(auto c : ans){
cout << c << " ";
}
}
上述做法的比较麻烦,效率不高,其实还有更好的做法,对每个单词做拆分,利用map
来对拆分的子串判断是否是输入之中的单词。代码如下:
"点击查看代码"
#include <iostream> #include <map> #include <string> #include <vector> #include <set> using namespace std; const int maxn = 120002; string sarr[maxn]; int main() { set
ans; int cnt = 0; map smap; while(cin >> sarr[cnt]){ smap[sarr[cnt]] = 1; ++cnt; } for(int i = 0; i < cnt; ++i){ for(unsigned j = 0; j < sarr[i].size(); ++j){ string a = sarr[i].substr(0, j+1); if(!smap.count(a)) continue; string b = sarr[i].substr(j+1); if(!smap.count(b)) continue; ans.insert(sarr[i]); break; } } for(auto c : ans) cout << c << " ";
}