Uva10191 复合词

题目描述:

给出一个按字母序排列的单词列表,找到其中存在的复合词。复合词的定义是由单词列表中其他的两个单词拼接而成。所有单词均为小写。

思路:

如果直接两层遍历所有的单词组合,看他们加在一起是否是单词列表中的一个,在输入如此大的情况下,肯定会超时。我的做法是,定义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;
vector svec[26];
string compound;
set ans;
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 << "\n";
}
}

上述做法的比较麻烦,效率不高,其实还有更好的做法,对每个单词做拆分,利用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 << "\n";

}

posted @ 2019-08-01 19:32  patrolli  阅读(190)  评论(0编辑  收藏  举报