目录
问题:1035:拼写检查
总时间限制:2000ms 内存限制:65536kB
描述
现在有一些英语单词需要做拼写检查,你的工具是一本词典。需要检查的单词,有的是词典中的单词,有的与词典中的单词相似,你的任务是发现这两种情况。单词A与单词B相似的情况有三种:
1、删除单词A的一个字母后得到单词B;
2、用任意一个字母替换单词A的一个字母后得到单词B;
3、在单词A的任意位置增加一个字母后得到单词B。
你的任务是发现词典中与给定单词相同或相似的单词。
输入
第一部分是词典中的单词,从第一行开始每行一个单词,以"#"结束。词典中的单词保证不重复,最多有10000个。
第二部分是需要查询的单词,每行一个,以"#"结束。最多有50个需要查询的单词。
词典中的单词和需要查询的单词均由小写字母组成,最多包含15个字符。
输出
按照输入的顺序,为每个需要检查的单词输出一行。如果需要检查的单词出现在词典中,输出“?x is correct",?x代表需要检查的单词。如果需要检查的单词没有出现在词典中,则输出"?x: ?x1 ?x2 ...?xn",其中?x代表需要检查的单词,?x1...?xn代表词典中与需要检查的单词相似的单词,这些单词中间以空格隔开。如果没有相似的单词,输出"?x:"即可。
样例输入
i
is
has
have
be
my
more
contest
me
too
if
award
#
me
aware
m
contest
hav
oo
or
i
fi
mre
#
样例输出
me is correct
aware: award
m: i my me
contest is correct
hav: has have
oo: too
or:
i is correct
fi: i
mre: more me
分析:
问题并不难,只要好好分析就可以做出来,不要被描述吓住。本题只要求有一个字母不同,所以可以分为三种情况:
1、完全相同,最好使用string类,直接使用“==”遍历字典判断就可以,
2、长度相等,这种情况直接将不相等的字母替换为相等的字母,然后对比两个单词是否相等,如果相等,则代表相似,如果不等,则代表不相似。
3、长度相差1个字母,在短字符串与长字符串不相等的那个位置,插入多出的那个字符。然后对比两个单词是否相等,如果相等,则代表相似,如果不等,则代表不相似。不想等的那个字母位置可能在中间,也可能在末尾,要考虑全。
扩展:如果我们想要获取和字典中单词有至多2个字母之差的单词,那么该如何处理,如果还是分情况讨论的话会非常复杂。这就需要使用BK树来解决,在我们使用字典app时,有没有发现即使输错几个字母,app依然能给我们推荐想要的单词,非常智能。详见:拼写检查编程题详解-BK树算法
C++AC代码:
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
using namespace std;
bool similar(string lonStr, string shorStr); //判断单词相似函数
int main()
{
vector<string> dictionary; //存储字典单词
vector<string>::iterator iter; //迭代器
string word; //需要检查的单词
string dic;
bool flag = false;
int sub =0;
while(1) //读入字典单词
{
cin >> dic;
if(dic == "#")
{
break;
}
dictionary.push_back(dic);
}
while(1) //依次判断
{
cin >> word;
if(word == "#")
{
break;
}
flag = false;
for(iter = dictionary.begin(); iter != dictionary.end(); iter++) //判断字典中是否存在该单词
{
dic = *iter;
if(dic == word)
{
cout << word << " is correct";
flag = true;
}
}
if(!flag) //如果字典中不存在,则查找是否有相似的单词
{
cout << word << ":";
for(iter = dictionary.begin(); iter != dictionary.end(); iter++) //遍历字典,判断是否相似
{
dic = *iter;
sub = dic.length() - word.length(); //获取两个单词长度之差,如果 <=1,则符合条件,如果>1则不可能匹配成功
if( sub== 0) //两个单词长度相同
{
for(int i=0; i< dic.length(); i++)
{
if(dic[i] != word[i])
{
string temp = word; //注意需要新建一个中间变量temp,不能直接修改单词word,因为之后还会用到word
temp[i] = dic[i]; //将不相等的单词替换为相等的单词,重新比较
if(temp == dic)
{
cout << " "<< dic ;
}
break;
}
}
}else if(abs(sub) == 1) //两个单词长度相差1个字母
{
if(dic.length() < word.length())
{
if(similar( word , dic )) //判断单词是否相似的函数similar()。
{
cout << " "<< dic;
}
}
else
{
if(similar(dic,word))
{
cout << " "<< dic ;
}
}
}
}
}
cout << endl;
}
return 0;
}
bool similar(string lonStr, string shorStr) //判断单词是否相似
{
int lon, shor;
lon = lonStr.length();
shor = shorStr.length();
string temp;
for(int i=0; i<shor; i++)
{
if(lonStr[i] != shorStr[i]) //遍历每个字母,找到不想等的字母位置
{
temp = shorStr.substr(0,i);
temp = temp + lonStr[i] + shorStr.substr(i,shor-i); //在较短的单词中插入不想等的字母,然后判断是否相等。
if(temp == lonStr)
{
return true;
}
}
}
temp = shorStr + lonStr[lon-1]; //以上判断会漏掉最后一个字母不想等的情况,这里补上。
if(temp == lonStr)
{
return true;
}
else
{
return false;
}
}
总结:
注意在修改时不能直接修改单词,应该使用一个中间变量(替身),因为原单词我们和字典中其他单词对比的时候还需要使用。
还有一个就是输出格式,
cout << " "<< dic ;
空格要在单词之前。