这题花的时间还真是不少呀,而且还是参考大牛思路的
题意:首先将字典保存,然后对应输入的message的每一个数字,输出频率最大的前缀,若没有,则输出MANUALLY
主要运用到了俩方面的知识,栈还有字典树,栈的实现主要是保存未遍历过节点,方便回溯
这里主要有俩个地方需要注意一下:
其一,就是每个单词中字母的频率,比如:“hell,3”和“hello ,4”,则前缀相同时,h的频率为4+3=7
其二,就是在利用栈进行回溯,首先将输入的串中对应的每一个数字调用find()函数查找最大频率的前缀,查找过程中,其实这里相当于深搜了,注意体会栈的思想
#include<iostream> #include<stack> using namespace std; struct node { int p;//记录频率 char c;//记录当前节点对应 的字母 node *next[26]; int lev;//记录层数 }; node *root; void insert(char *s,int p)//插入一个单词 { node *por=root; for(;*s!='\0';s++) { int d=*s-'a'; if(por->next[d]==NULL) { por->next[d]=new node(); por->next[d]->p=p; por->next[d]->c=*s; } else { por->next[d]->p+=p;//计算当前字母的频率 } por=por->next[d]; } } void find(char *s,int e) { int table[10][4]={{},{},{0,1,2,0},{3,4,5,0},{6,7,8,0},{9,10,11,0},{12,13,14,0},{15,16,17,18},{19,20,21,0},{22,23,24,25}};//按键数字对应的字符映射表 int max=0; node *por=root,*cur=root,*nex; char word[101],ans[101];//word记录当前字母的前缀,ans记录频率最大的字母的前缀 stack<node*> nd; nd.push(cur); cur->lev=-1; while(!nd.empty()) { cur=nd.top(); nd.pop(); if(cur->lev>-1) word[cur->lev]=cur->c;//记录前缀 if(cur->lev==e) { if(cur->p>=max)//等号不能省,当频率相同时,按字典序小的输出,而因为用栈压入的节点,所以字典序大的节点先访问了 { max=cur->p; for(int i=0;i<=e;i++)//到达对应输入串的层数且频率最大时,将当前word保存的前缀赋给ans { ans[i]=word[i]; } } } else { int n=(s[cur->lev+1]=='7'||s[cur->lev+1]=='9')?4:3;//注意7号键和9号键与其他数字键的区别 for(int i=0;i<n;i++) { int d=table[s[cur->lev+1]-'0'][i];//s[cur->lev+1]表示下一层对应的数字,d表示数字键中映射的字母的序号 nex=cur->next[d]; if(nex!=NULL) { nex->lev=cur->lev+1;//下一节点的层数+1 nd.push(nex);//压入栈 } } } } if(max==0) cout<<"MANUALLY"<<endl; else { ans[e+1]='\0'; cout<<ans<<endl;//输入最大频率的前缀 } } void del(node *por)//清除字典树 { for(int i=0;i<26;i++) { if(por->next[i]!=NULL) del(por->next[i]); } delete por; } int main() { int cas,k=0,n,m,i,j,p; char word[105],str[105]; cin>>cas; while(cas--) { cin>>n; root=new node(); while(n--) { cin>>word>>p; insert(word,p); } cout<<"Scenario #"<<++k<<':'<<endl; cin>>m; while(m--) { cin>>str; int len=strlen(str)-1; for(i=0;i<len;i++) find(str,i); cout<<endl; } cout<<endl; del(root); } return 0; }