逆序单词 HIhoCoder 1366 字典树

逆序单词 HIhoCoder 1366 字典序

题意

在英文中有很多逆序的单词,比如dog和god,evil和live等等。

现在给出一份包含N个单词的单词表,其中每个单词只出现一次,请你找出其中有多少对逆序单词。

第1行:1个整数,N,表示单词数量。2≤N≤50,000。

第2..N+1行:每行1个单词,只包含小写字母,每个单词长度不超过16个字母。保证每个单词只出现一次,且不会出现回文单词(即一个单词倒序还是它自己,比如eye)。

输出第一行是个整数,表示单词表中的逆序单词的对数。

解题思路

这个是我看B站学习字典序上看到的题,基本是个模板题。详情看代码实现吧。

代码实现

字典树大体有两种实现方式,区分是从结点的建立上,一种是使用new分配空间建立,另一种是预先开辟一个数组。

下面是两种形式的代码。第二种运行比较快。

#include<bits/stdc++.h> //时间是453ms
using namespace std;
struct Node
{
    Node *next[26]; //对应26个小写英文字母
    int flag; //这个记录从根节点到现在这个结点组成的单词是不是存在的单词,如果有多个的话,可以记录个数。
    Node()//构造函数
    {
        for(int i=0; i<26; i++)
            next[i]=NULL;
        flag=0;
    }
}*root;//这个root是字典树的第一个结点,也就是树的根。

void insert(char *s) //插入操作
{
    int len=strlen(s);
    Node *now = root;
    for(int i=len-1; i>=0; i--) //根据题目要求,这里使用逆序插入比较好。
    {
        int to=s[i]-'a';
        if(now->next[to]==NULL) //如果没有子节点,就建立。
            now->next[to]=new Node();
        now=now->next[to];//然后进入到下一个单词的子节点。
    }
    now->flag++; //可能有多个单词
}
int fid(char *s)//查找函数
{
    int len=strlen(s);
    Node *now=root;
    for(int i=0; i<len; i++)//这里就是正向查找了
    {
        int to=s[i]-'a';
        if(now->next[to]==NULL)
            return 0;
        now=now->next[to];
    }
    return now->flag;//返回以这个结点为尾的单词的个数
}
void del(Node *rot) //因为使用的是new分配的空间,所以使用完毕需要进行删除。
{
    for(int i=0; i<26; i++)
    {
        if(rot->next[i])
            del(rot->next[i]);//递归形式的删除。
    }
    delete(rot);
}
int main()
{
    int n, ans=0;
    char op[20];
    root = new Node();
    scanf("%d",&n);
    getchar();
    for(int i=0; i<n; i++)
    {
        scanf("%s", op);
        ans+=fid(op);
        insert(op);
    }
    printf("%d\n", ans);
    del(root);
    return 0;
}
#include<bits/stdc++.h> //时间是242ms
using namespace std;
const int maxn=2e6+7;
int tree[maxn][27];
int flag[maxn];
int tot;
void insert(char *str)
{
    int len=strlen(str);
    int root=0;
    for(int i=len-1; i>=0; i--)
    {
        int id=str[i]-'a';
        if(!tree[root][id])
            tree[root][id]=++tot; //类似于邻接链表的形式来建立
        root=tree[root][id];
    }
    flag[root]++;
}
int find(char *str) //需要根据需要进行匹配
{
    int len=strlen(str);
    int root=0;
    for(int i=0; i<len; i++)
    {
        int id=str[i]-'a';
        if(!tree[root][id])
            return 0;
        root=tree[root][id];
    }
    return flag[root];
}
int main()
{
    int n, ans=0;
    char op[20];
    scanf("%d",&n);
    getchar();
    for(int i=0; i<n; i++)
    {
        scanf("%s", op);
        ans+=find(op);
        insert(op);
    }
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/alking1001/p/11762089.html

时间: 2024-11-09 10:43:03

逆序单词 HIhoCoder 1366 字典树的相关文章

【oiClass1502】查单词(Trie字典树)

题目描述 全国英语四级考试就这样如期来了,可是小y依然没有做好充分准备.为了能够大学毕业,可怜的小y决定作弊.小y费尽心机,在考试的时候夹带了一本字典进考场,但是现在的问题是,考试的时候可能有很多的单词要查,小y能不能来得及呢? 输入 第一行一个整数N,表示字典中一共有多少个单词(N<=10000).接下来每两行表示一个单词,其中:第一行是一个长度<=100的字符串,表示这个单词,全部小写字母,单词不会重复.第二行是一个整数,表示这个单词在字典中的页码.接下来是一个整数M,表示要查的单词数(M

[HIHO1366]逆序单词(水题)

题目链接:http://hihocoder.com/problemset/problem/1366 题意:中文题 正着倒着存一遍,看看有几个出现了>1次,结果除以2 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 50500; 5 char s[maxn], t[maxn]; 6 int n; 7 map<string, int> ok; 8 9 int main() { 10 //

leetcode 820. 单词的压缩编码(字典树)

给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A. 例如,如果这个列表是 ["time", "me", "bell"],我们就可以将其表示为 S = "time#bell#" 和 indexes = [0, 2, 5]. 对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 "#" 结束,来恢复我们之前的单词列表. 那么成功对给定单词列表进行编码的最小字符串

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

Codeforces 633 C Spy Syndrome 2 字典树

题意:还是比较好理解 分析:把每个单词反转,建字典树,然后暴力匹配加密串 注:然后我就是特别不理解,上面那种能过,而且时间很短,但是我想反之亦然啊 我一开始写的是,把加密串进行反转,然后单词正着建字典树,然后就TLE了,反着写就能过 真是百思不得解,然后我猜测可能是单词数目比较少 #include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <v

URAL 1542. Autocompletion 字典树

给你最多10w个单词和对应的频率 接下来最多1w5千次询问 每次输入一个字符串让你从前面的单词中按照频率从大到小输出最多10个以该字符串为前缀的单词 开始把单词建成了字典树 然后每次询问找到所有满足条件的单词 在排序输出 不是超时就是超内存 还来了一发数组越界 最后换方法 因为最多只要输出前10个 那么可以把要询问的字符串建字典树 每个结尾节点在做一个映射 存10个单词(当然只是存下标) 然后再把单词按照频率从大到小排序一个一个插入字典序 满足有前缀是结尾节点就放进去 #include <cst

[ACM] hdu 1251 统计难题 (字典树)

统计难题 Problem Description Ignatius近期遇到一个难题,老师交给他非常多单词(仅仅有小写字母组成,不会有反复的单词出现),如今老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). Input 输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每一个提问都是一个字符串. 注意:本题仅仅有一组測试数据,处理到文件结束. Out

HDU 1251 统计难题(字典树 裸题 链表做法)

Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). Input 输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串. 注意:本题只有一组测试数据,处理到文件结束. Output 对于每个提

Time Limit Exceeded 求逆序对数。

/** 题目:Time Limit Exceeded 链接:https://oj.ejq.me/problem/28 题意:求逆序对数. 思路:树状数组求逆序对数.维护前面有多少个<=当前数的数的个数. */ #include<bits/stdc++.h> typedef long long ll; using namespace std; const int maxn = 1e6+10; const int mod = 1e9+7; ll c[maxn]; int flag[maxn]