莫尔斯代码这道题目题意说的非常的不清晰,还好在网上看了别人的代码,然后才完全明白了问题是什么
描述如下:
输入一串莫尔斯代码,去寻找与之匹配的word
如果可以精准匹配,那么输出所有可以精准匹配里面字典序最小的;如果只有1个,那么不用加!,如果有多个,那么需要加!
如果不可以精准匹配,而只能模糊匹配的话,模糊匹配就是可以在末尾加上或者去掉几个莫尔斯代码就能够精准匹配的情况。输出加上或者去掉最少的而且字典序最小的。并在末尾加上?
先贴上我的代码:
#include<cstdio> #include<map> #include<algorithm> #include<cstdlib> #include<iostream> #include<string> #include<set> using namespace std; //主要难点:字符串的操作,以及,什么叫做可以从末尾截断和添加,这吉尔也说的太模糊了 //这题考字符串的操作:即如何从word构造出对应的string版本的morse编码 //还考数据结构的构造,构造出合适的数据结构,使得搜索的时候变得简单,有多个精确匹配的时候,需要输出字典序最小的。 map<char,string>letter_morse; map<string,char>morse_letter; struct words { int size; set<string>Set; }; map<string,words*>morse_words;//存储morse相同的words,其中morse中的words需要按照字典序排序,这样一来,在后面输入morse的时候,进行匹配的时候,直接和这个map的morse比较就可以了 void read_table() { for(;;) { string letter,morse; cin>>letter; if(letter[0]=='*') return; cin>>morse; letter_morse[letter[0]]=morse; //cout<<letter<<" "<<letter_morse[letter[0]]<<endl; morse_letter[morse]=letter[0]; } } void read_dic() { for(;;) { string word; cin>>word; if(word[0]=='*') return; //cout<<letter<<" "; string morse=""; for(int i=0;i<word.size();i++) { morse=morse+letter_morse[word[i]];//字符串的赋值 } if(!morse_words.count(morse))//原来里面没有这个东西 { morse_words[morse]=new words; morse_words[morse]->Set.insert(word);//插入一个 morse_words[morse]->size=1; } else//这样一来就全部弄进去了,而且set里面就是已经保存好的字典序 { morse_words[morse]->Set.insert(word); morse_words[morse]->size++; } //printf("\n"); } } void print_map() { map<string,words*>::iterator it=morse_words.begin(); for(;it!=morse_words.end();it++) { cout<<it->first<<" "; for(set<string>::iterator set_it=it->second->Set.begin();set_it!=it->second->Set.end();set_it++) { cout<<*set_it<<" "; } printf("%d",it->second->size); printf("\n"); } } bool read_morse() { string morse; cin>>morse; //cout<<morse<<endl; if(morse[0]=='*') return false; map<string,words*>::iterator it=morse_words.begin(); int cnt=100;//保存可能匹配的情况下,不匹配的字符数有多少(模糊匹配时是一个正数,精确匹配时,是0) string mohu; int kase=0; for(;it!=morse_words.end();it++) { int flag=1;//1表示相同,0表示不同 if(abs((int)it->first.size()-(int)morse.size())>cnt)//说明此时要么不匹配,要么可能模糊匹配但是不同的字符数过多 { continue;//应该去尝试map中的下一个string } for(int i=min(it->first.size(),morse.size())-1;i>=0;i--)//如果有可能匹配,即不管是精确还是模糊,从i开始向后退,一定是一样的。 { if(morse[i]!=it->first[i]) { flag=0; break; } } if(!flag) { continue;//无法匹配,需要到下一个 } //cout<<*it->second->Set.begin()<<endl; //cout<<it->first.size()<<" "<<morse.size()<<endl; //cout<<cnt<<endl; if(abs((int)it->first.size()-(int)morse.size())==0)//此时精确匹配 { cout<<*it->second->Set.begin(); if(it->second->size!=1) { printf("!"); } printf("\n"); return true; } if(abs((int)it->first.size()-(int)morse.size())<cnt)//这次匹配的时候,不一样的字符更少 { mohu=*it->second->Set.begin(); cnt=abs((int)it->first.size()-(int)morse.size()); } //如果不是精确匹配,说明此时是模糊匹配,此时需要比较这两个模糊匹配的最小字典序哪一个小 else if(*it->second->Set.begin()<=mohu)//这个时候,这次匹配和上次匹配不一样的字符是一样的 { mohu=*it->second->Set.begin(); } } cout<<mohu<<"?"<<endl; return true; } int main() { #ifdef local freopen("input.txt","r",stdin); freopen("out2.txt","w",stdout); #endif read_table(); read_dic(); //print_map(); while(read_morse()); return 0; }
正如我所说的,这道题目考察对数据结构的组织能力:
我的组织方式是这样的,翻译context中每个单词所对应的莫尔斯代码,然后使用map《莫尔斯,单词》的方式来进行映射,这样一来,在后面直接搜寻的过程中,就直接直接用输入的要匹配的莫尔斯代码来查询。而且后面的单词是一个结构体。结构体里面有一个《set》,set中保存的是符合这个莫尔斯代码的单词,并且按照字典序排序。
一直到上一步,我的想法都是正确的。但是接下来就有了一点问题,虽然结果是正确的。
在接下来开始匹配的过程中,我过多的去想要一次遍历就能够匹配成功,即遍历map一次,就可以判断出它是精准匹配还是模糊匹配。其实不必这么做,因为遍历两次也花费不了多少时间,最多是两倍的时间。
在匹配的过程中有一个很好的思路,就是,只要能够匹配,那么min(输入的morse,表里面的morse)一定是相同的。这一点可以很好的利用。
在输入单词和莫尔斯代码的映射表的时候,字符串的处理也是一个值得学习的地方。即string s=""; s=s+anther_string.这样可以拼凑出字符串。