zoukankan      html  css  js  c++  java
  • 逆序单词 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
    ", 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
    ", ans);
    	return 0;
    }
    
    欢迎评论交流!
  • 相关阅读:
    数据库三,exec内置函数
    HDU 1003:Max Sum(DP,连续子段和)
    HDU 1024:Max Sum Plus Plus(DP,最大m子段和)
    Codeforces 698A:Vacations(DP)
    牛客多校第五场 J:Plan
    51Nod 1091:线段的重叠(贪心)
    ZZNU 2125:A + B 普拉斯(傻逼题+大数加法)
    HDU 1010:Tempter of the Bone(DFS+奇偶剪枝+回溯)
    HDU 1176:免费馅饼(DP,自认为很详细的解释)
    POJ 2312:Battle City(BFS)
  • 原文地址:https://www.cnblogs.com/alking1001/p/11762089.html
Copyright © 2011-2022 走看看