Trie 字典树

1、UVa 1401 Remember the Word

  题意:给出n个字符串集合,问其有多少种组合方式形成目标字符串。

  思路:对n个字符串集合建立Trie树,保存每个结点的字符串的顺序编号。然后对这棵树查找目标字符串每一个后缀的前缀字符串,累加。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<vector>
 6 using namespace std;
 7 const int MOD = 20071027;
 8 struct Trie
 9 {
10     int word[4001 * 100][26];
11     int ex[4001 * 100];
12     int size;
13
14     void clear()
15     {
16         memset(word[0], 0, sizeof(word[0]));
17         size = 1;
18         ex[0] = 0;
19     }
20
21     void insert(char *s, int v)
22     {
23         int Now = 0, curchr;
24         for (int i = 0; s[i] != ‘\0‘; i++)
25         {
26             int c = s[i] - ‘a‘;
27             if (!word[Now][c])
28             {
29                 memset(word[size], 0, sizeof(word[size]));
30                 ex[size] = 0;
31                 word[Now][c] = size++;
32             }
33             Now = word[Now][c];
34         }
35         ex[Now] = v;
36     }
37
38     int search(char *s, int len, vector<int>& ans)
39     {
40         int u = 0, c;
41         for (int i = 0; s[i] != ‘\0‘&&i<len; i++)
42         {
43             c = s[i] - ‘a‘;
44             if (!word[u][c])return 0;
45             u = word[u][c];
46             if (ex[u])
47                 ans.push_back(ex[u]);
48         }
49     }
50 } tree;
51
52 char s[300001];
53 char tmp[101];
54 int dp[300001];
55 int n;
56 int ll[4001];//记录每个字符串的长度
57 int main()
58 {
59     int Case = 1;
60     while (~scanf("%s",s))
61     {
62         scanf("%d", &n);
63         tree.clear();
64         memset(dp, 0, sizeof(dp));
65         int len = strlen(s);
66
67         for (int i = 0; i<n; i++)
68         {
69             scanf("%s", tmp);
70             ll[i + 1] = strlen(tmp);
71             tree.insert(tmp, i + 1);
72         }
73         dp[len] = 1;
74         for (int i = len - 1; i >= 0; i--)
75         {//找下标为i~len-1的子字符串的前缀字符串
76             vector<int>ans;
77             tree.search(s + i, len - i, ans);
78             for (int j = 0; j<ans.size(); j++)
79                 dp[i] = (dp[i] + dp[i + ll[ans[j]]]) % MOD;
80         }
81         printf("Case %d: %d\n", Case++, dp[0]);
82     }
83     return 0;
84 }

2、UVA 11732 strcmp() Anyone?

  题意:给n个长度不超过1000的字符串,两两字符串比较,某一位相同比较2次,不相同比较1次,问需要比较多少次。

  思路:左儿子右兄弟法表示Trie树。向右找相同字符,向左添加新字符,同一兄弟层表示在同一位的字符。

  参考:http://www.cnblogs.com/sineatos/p/3888815.html

 1 #include <cstdio>
 2 #include <cstring>
 3 #define MAXN 4001010
 4 #define ll long long
 5 using namespace std;
 6 //左儿子右兄弟表示字典树
 7 int head[MAXN];// head[i]为第i个结点的左儿子编号
 8 int next[MAXN];// next[i]为第i个结点的右兄弟编号
 9 int tot[MAXN];// tot[i]为第i个结点为根的子树包含的叶结点(即以包含其的前缀的字符串个数)总数
10 int ed[MAXN];// ed[i]为第i个结点结束的字符串的个数
11 char ch[MAXN];// ch[i]为第i个结点上的字符
12 int sz;
13 ll sum;
14 void init()
15 {// 初始时只有一个根结点
16     sz = 1; head[0] = next[0] = tot[0] = 0; sum = 0;
17 }
18
19 void insert(char *s)
20 {
21     int u, v, n = strlen(s);
22     u = 0;
23     for (int i = 0; i<n; i++)
24     {
25         bool f = 0;
26         for (v = head[u]; v != 0; v = next[v])
27         {//找字符s[i]
28             if (ch[v] == s[i])
29             {
30                 f = 1; break;
31             }
32         }
33         if (!f)
34         {//如果没找到,新建结点
35             v = sz++;
36             tot[v] = 0;
37             ed[v] = 0;
38             ch[v] = s[i];
39             next[v] = head[u];//插入首部
40             head[u] = v;
41             head[v] = 0;
42         }
43         u = v;
44         sum += tot[v] * 2;
45         tot[v]++;
46     }
47     sum += ed[u];
48     ed[u]++;
49 }
50 int main()
51 {
52     int n;
53     char s[1002];
54     int Case = 1;
55     while(~scanf("%d", &n)&&n)
56     {
57         init();
58         for (int i = 0; i<n; i++)
59         {
60             scanf("%s", s);
61             insert(s);
62         }
63         printf("Case %d: %lld\n", Case++, sum + n*(n - 1) / 2);
64     }
65     return 0;
66 }

3、uva 11488  Hyper Prefix Sets

  题意:求n个给出的01串的最长公共前缀的长度*n的值。

  思路:字典树,每次插入一个新的01串,累计每个结点的前缀的长度。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5
 6 const int maxn = 10000010;
 7 const int Char_size = 2;
 8 struct Trie
 9 {
10     int word[maxn][Char_size];//结点
11     int val[maxn];//附加信息
12     int size;//总结点数
13     int ans;
14
15     void Init()
16     {
17         memset(word[0], 0, sizeof(word[0]));
18         size = 1;
19         val[0] = 0;
20         ans = 0;
21     }
22     int getID(char c)
23     {
24         return c - ‘0‘;
25     }
26     void Insert(char *s)
27     {
28         int now = 0, curchr;
29         for (int i = 0; s[i] != ‘\0‘; i++)
30         {
31             int pos =getID(s[i]);
32             if (!word[now][pos])
33             {
34                 memset(word[size], 0, sizeof(word[size]));
35                 val[size] = 0;
36                 word[now][pos] = size++;
37             }
38             now = word[now][pos];
39             val[now] += i + 1;//累加到该结点的前缀的长度
40             ans = max(ans, val[now]);
41         }
42     }
43 }tree;
44
45 char str[maxn];
46 int main()
47 {
48     int t;
49     scanf("%d", &t);
50     while (t--)
51     {
52         tree.Init();
53         int n;
54         scanf("%d", &n);
55         while (n--)
56         {
57             scanf("%s", str);
58             tree.Insert(str);
59         }
60         printf("%d\n", tree.ans);
61     }
62     return 0;
63 }

时间: 2024-11-06 01:21:09

Trie 字典树的相关文章

DFA和trie字典树实现敏感词过滤(python和c语言)

现在做的项目都是用python开发,需要用做关键词检查,过滤关键词,之前用c语言做过这样的事情,用字典树,蛮高效的,内存小,检查快. 到了python上,第一想法是在pip上找一个基于c语言的python字典树模块,可惜没找到合适的,如果我会用c写python模块的话,我就自己写一个了,可惜我还不具备这个能力, 只能用python写了,性能差一点就差点吧,内存多一点也无所谓了. 用搜索引擎看CSDN上的网友的用python实现的DFA,再参照自己以前用c语言写过的字典树,有些不大对,就自己写了一

Trie 字典树 删除操作

字典树的删除操作: 1 没找到直接返回 2 找到叶子节点的时候,叶子节点的count标志清零,代表不是叶子节点了 3 如果当前节点没有其他孩子节点的时候,可以删除这个节点 判断是否需是叶子节点,就检查叶子节点的count标志就可以了. 判断是否有其他孩子节点就需要循环26个节点了,如果都为空,那么就没有其他孩子节点了. #include <stdio.h> #include <stdlib.h> #include <iostream> #include <vect

Trie字典树 动态内存

Trie字典树 1 #include "stdio.h" 2 #include "iostream" 3 #include "malloc.h" 4 #include "string.h" 5 6 using namespace std; 7 8 #define MAX_SIZE 26 9 10 typedef struct Trie{ 11 char val; 12 bool isword; 13 struct Trie*

萌新笔记——C++里创建 Trie字典树(中文词典)(插入、查找、遍历、导入、导出)(上)

写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示一串可能要搜索的东西. 首先放上最终的结果: input: 1 编程入门 2 编程软件 3 编程学习 4 编程学习网站 output: 1 char : 件 2 word : 编程软件 3 char : 习 4 word : 编程学习 5 char : 网 6 word : 编程学习网 7 char : 门 8 word : 编程入门 其实这里不应

算法导论:Trie字典树

1. 概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie一词来自retrieve,发音为/tri:/ “tree”,也有人读为/tra?/ “try”. Trie树可以利用字符串的公共前缀来节约存储空间.如下图所示,该trie树用10个节点保存了6个字符串pool.prize.preview.prepare.produce.progress 在该trie树中,字符串preview,prepa

trie/字典树几题

以后有好多次看到这地方就过去了, 未亲自实践过. 不过今晚看了一下,感觉trie的思想还算是比较基础的. 感觉这一个链接讲的不错:http://www.cnblogs.com/BeyondAnyTime/archive/2012/07/16/2592838.html 顺便水了几道题. 具体列表可见:http://vjudge.net/contest/view.action?cid=47036#overview A:水题啦. 稍微理解下trie就能写出来了. 附个自己写的代码,还是用LRJ书上的非

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

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

LeetCode 208.实现Trie(字典树) - JavaScript

??Blog :<LeetCode 208.实现Trie(字典树) - JavaScript> 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作. Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // 返回 true trie.search("app"); // 返回 false trie.

Trie字典树 静态内存

静态字典树 看了好久的字典树,挺简单的一个结构,愣是看了这么久才写出来... 专心一点就不会这样了.... 接下来就去刷刷字典树的题吧....... 下面是字典树.... 定义节点 typedef struct Trie{ char val;  //其实这东西没啥软用...注释掉也一样...没有变化 bool isword; struct Trie *next[26];}*Trie_pointer; 然后建树 这几天抽风了... 把memset写在函数外面去了.... 编译老半天过不去....