AOJ-AHU-OJ-673 聪明的输入法

37 篇文章 0 订阅
7 篇文章 0 订阅
聪明的输入法
Time Limit: 10000 ms   Case Time Limit: 2000 ms   Memory Limit: 128 MB
Description
众所周知,XX输入法具备强大的学习功能,对于用户来说,感觉输入法像一个会学习的机器人,比如,当用户第一次输入“sxl”,输入法第一个提示“少写了”,
如果用户选择“睡醒了”,当第二次用户再输入“sxl”的时候,“睡醒了”这个词就会出现在比较靠前的位置,神奇吧,输入法就像一个小孩子,在你的指导下慢慢学会每个拼音的含义。
现在让我们一起来实现下这个神奇的功能吧,为方便起见,我们假设用户是美国籍的(仅输入小写英语字母),每当该用户输入一个单词时,请输出和该用户输入习惯最为匹配的单词(以该单词为前缀的输入频率最高的单词),如果有多个则输出字典序最小的,如果没有的话,则直接输出该单词。

Input
单组测试数据
第一行输入一个整数N(1<= n <= 10 5),表示用户输入单词的个数。
接下来N行由小写字母组成的英文单词,每个单词的长度大于0且不超过10。

Output
请输出n个最为匹配的单词,
第i行输出对应第i个输入单词。

Sample Input
Original Transformed
5
abc
abd
abc
ab
a

Sample Output
Original Transformed
abc
abd
abc
abc
abc

Source
“讯飞输入法杯”安徽大学第六届程序设计竞赛
————————————————————忧桑的分割线————————————————————
思路:字典树的应用……难度还是有的。但是学姐的解题报告上说该题是模板题,题解省略,QAQ。思路是酱紫的:在字典树的数据域储存三样东西:1.单词出现次数 2.以该单词为前缀的单词的最大频率 3.以该单词为前缀的最大频率的单词。
每完成一次输入(插入),都需要做以下两件事:1.输出答案 2.逆向维护这个字典
对字典树的逆向维护是比较困难的……假如你不熟悉递归的话。因为只能从根结点开始向下找儿子,而维护的时候,一路上的父亲都要维护。那么DFS是非常必要的。将Insert()函数改写成递归即可。模板Insert的思路是一个for循环插入一个单词,现在改成DFS整个单词,一个字母一个字母Insert,在递归的边界上输出之前维护好的答案。输出之后在return每一层DFS的过程中,维护这个字典树。
代码如下:
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
const int MAXN = 1000010;
int nxt;
char dic[15];
struct Trienode {
    Trienode* next[26];
    int cnt, maxi;
    char str[15];
}trie[MAXN];

Trienode* newnode() {
    memset(&trie[nxt], 0, sizeof(Trienode));
    return &trie[nxt++];
}

int Insert(Trienode* rt, char* s) {
    if(s[0] == '\0') {
		//维护好的字典树上储存的都是最大频率单词,故不会出现该单词之前出现的频率大于最大频率
        if(rt->cnt == rt->maxi)//就两种情况:1.之前出现该单词的频率和最大一样;2.当前单词没出现过(cnt = maxi = 0)
            printf("%s\n", dic);//由于按字典序输出,所以频率一样的时候,该单词的字典序一定是最小的(它本身就是最短前缀)
        else
            printf("%s\n", rt->str);
        rt->cnt++;//题干要求在输入时只考虑之前的出现频率
        return rt->cnt;
    }
    else {
        int c = s[0] - 'a';
        if(!rt->next[c]) rt->next[c] = newnode();
        rt = rt->next[c];
        int ret = Insert(rt, s+1);//递归插入单词,一个字母一个字母来。边界条件是该单词插完
        if(ret > rt->maxi) {
            strcpy(rt->str, dic);
            rt->maxi = ret;
        }
        else if(ret == rt->maxi&&strcmp(rt->str, dic) > 0)
            strcpy(rt->str, dic);
        //以上是两种情况的维护:最大频率改变;字典序
        return ret;//逆向维护字典树,每一层DFS返回一个ret,表示频率
    }
}

int main() {
    nxt = 0;
    Trienode* root = newnode();
    int cas;
    scanf("%d", &cas);
    while(cas--) {
        scanf("%s", dic);
        Insert(root, dic);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值