#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define kind 26
const int MAXN = 10000000;
struct node
{
int count; //是否为单词最后一个节点
node *next[26];//Trie每个节点的26个子节点
node *fail; //失败指针
};
node *q[MAXN]; //队列,采用bfs 构造失败指针
char keyword[55];//输入单词 模式串
char str[1000010];// 需要查找的 主串
int head,tail;//队列 头尾指针
node *root;
void insert(char *word,node *root)
{
int index,len;
node *p = root,*newnode;
len = strlen(word);
for(int i=0 ;i < len ; i++ )
{
index=word[i]-'a';
if(!p->next[index])//该字符节点不存在,加入Trie树中
{
// 初始化 newnode 并 加入 Trie 树
newnode=(struct node *)malloc(sizeof(struct node));
for(int j=0;j<26;j++) newnode->next[j]=0;
newnode->count=0;newnode->fail=0;
p->next[index]=newnode;
}
p=p->next[index];//指针移动至下一层
}
p->count++; //单词结尾 节点 count + 1 做标记
}
void build_ac_automation(node *root)
{
head=0;tail=1;
q[head]=root;
node *temp,*p;
while(head<tail)//bfs构造 Trie树的失败指针
{
//算法类似 kmp ,这里相当于得到 next[]数组
//重点在于,匹配失败时,由fail指针回溯到正确的位置
temp=q[head++];
for(int i=0;i< 26 ;i ++)
{
if(temp->next[i])//判断实际存在的节点
{
// root 下的第一层 节点 都 失败指针都 指向root
if(temp==root) {
temp->next[i]->fail=root;
}
else {
//依次回溯 该节点的父节点的失败指针
//知道某节点的next[i]与该节点相同,则
//把该节点的失败指针指向该next[i]节点
//若回溯到 root 都没有找到,则该节点
//的失败指针 指向 root
p=temp->fail;//temp 为节点的父指针
while(p){
if(p->next[i]){
temp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if(!p)temp->next[i]->fail=root;
}
//每处理一个点,就把它的所有儿子加入队列,
//直到队列为空
q[tail++]=temp->next[i];
}
}
}
}
int query(node *root)//类似于 kmp算法。
{
//i为主串指针,p为匹配串指针
int i,cnt=0,index,len=strlen(str);
node *p=root;
for(i=0; i < len ;i ++)
{
index=str[i]-'a';
//由失败指针回溯寻找,判断str[i]是否存在于Trie树种
while(!p->next[index] && p != root)p=p->fail;
p=p->next[index];//找到后 p 指向该节点
//指针回为空,则没有找到与之匹配的字符
if(!p)p=root;//指针重新回到根节点root,下次从root开始搜索Trie树
node *temp=p;//匹配该节点后,沿其失败指针回溯,判断其他节点是否匹配
while(temp != root )//匹配 结束控制
{
if(temp->count>=0)//判断 该节点是否被访问
{
//统计出现的单词个数cnt,由于节点不是单词结尾时count为0,
//故 cnt+=temp->count; 只有 count >0时才真正统计了单词个数
cnt+=temp->count;
temp->count=-1; //标记已访问
}
else break;//节点已访问,退出循环
temp=temp->fail;//回溯失败指针继续寻找下一个满足条件的节点
}
}
return cnt;
}
int main()
{
int i,t,n,ans;
scanf("%d",&t);
while(t--)
{
root=(struct node *)malloc(sizeof(struct node));
for(int j=0;j<26;j++) root->next[j]=0;
root->fail=0;
root->count=0;
scanf("%d",&n);
getchar();
for(i=0;i<n;i++)
{
gets(keyword);
insert(keyword,root);
}
build_ac_automation(root);
gets(str);
ans=query(root);
printf("%d\n",ans);
}
return 0;
}
//hdu2222需要做的。
很好的字符串处理题目
求多个字符串的公共字串,由于数据比较小,可以暴力求解。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char str[15][80];
int n, m;
int main()
{
scanf("%d", &n);
while(n--) {
scanf("%d", &m);
getchar();
for(int i = 0; i < m; i++) {
scanf("%s", str[i]);
}
char s1[70];
char ans[70];
int t = 0;
int len = strlen(str[0]);
for(int i = 0; i < len; i++) {
for(int j = i + 2; j < len; j++) { //枚举所以大于3的字串,
strncpy(s1, str[0]+i, j - i + 1); //此函数拷被后,没在字符串后面加‘\0',
s1[j-i + 1] = '\0'; //需手动加上,
// printf("%s\n", s1);
int flag = 1;
for(int k = 1; k < m&&flag; k++) {
if(strstr(str[k], s1) == NULL) { //简单的匹配查找函数。
flag = 0;
}
}
// printf("%d\n", flag);
if(flag) {
if(t == 0) {
strcpy(ans, s1); //函数的复制。
t++;
}else {
int ans1 = strlen(ans);
int slen = strlen(s1);
if(ans1 < slen) {
strcpy(ans, s1);
}else if(ans1 == slen && strcmp(ans, s1) > 0) {
strcpy(ans, s1);
}
}
}
}
}
if(t != 0) {
printf("%s\n", ans);
}else {
printf("no significant commonalities\n");
}
}
return 0;
}
关于字符串处理专题的总结:
poj 1002
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
/*应注意
2
0000000
0000000
output
000-0000 2
*/
//用sort排序老超时,
/*
现在想想题目还是很简单的,
方法1
将输入的电话号码转换成整数, hash就好了,
注意:如果用整数输出,
printf("%03d-%04d %d\n", i/10000, i%10000, num[i]);
对七位全为0的整数输出。
*/
char map[26] = {'2', '2', '2', '3', '3', '3', '4', '4', '4',
'5', '5', '5', '6', '6', '6', '7', '0', '7', '7', '8', '8', '8', '9', '9', '9', '0'
};
char str1[305];
int num[10000005];
int n;
int main()
{
char str[300];
while(scanf("%d", &n) != EOF)
{
memset(num, 0, sizeof(num));
int maxn = 0, minn = 10000000;
int flag = 0;
for(int i = 0; i < n; i++)
{
scanf("%s", str1);
int k = 0;
for(int j = 0; str1[j] != '\0'; j++)
{
if(str1[j] == '-' || str1[j] == 'Q' || str1[j] == 'Z')
continue;
if(str1[j] >= 'A' && str1[j] <= 'Z')
{
str[k++] = map[str1[j]-'A'];
}
if(str1[j] >= '0' && str1[j] <= '9')
{
str[k++] = str1[j];
}
}
str[k] = '\0';
int ans = atoi(str);
if(ans > maxn)
maxn = ans;
if(ans < minn)
minn = ans;
num[ans]++;
}
for(int i = minn; i <= maxn; i++) {
if(num[i] > 1) {
printf("%03d-%04d %d\n", i/10000, i%10000, num[i]);
flag = 1;
}
}
if(!flag)
printf("No duplicates.\n");
}
return 0;
}
poj2141
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
using namespace std;
char str[30];
char str1[100];
int main()
{
while(scanf("%s", str) != EOF) {
map<char,char>m;
for(int i = 0; i < 26; i++){
m['a' + i] = str[i];
}
getchar();
gets(str1);
for(int j = 0; str1[j]; j++) {
if(str1[j] == ' '){
printf(" ");
} else if(str1[j] >= 'a' && str1[j] <= 'z'){
printf("%c", m[str1[j]]);
}
else if(str1[j] >= 'A' && str1[j] <= 'Z') {
printf("%c", m[str1[j] + 32] - 32);
}
}
printf("\n");
}
return 0;
}
poj3080
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char str[15][80];
int n, m;
int main()
{
scanf("%d", &n);
while(n--) {
scanf("%d", &m);
getchar();
for(int i = 0; i < m; i++) {
scanf("%s", str[i]);
}
char s1[70];
char ans[70];
int t = 0;
int len = strlen(str[0]);
for(int i = 0; i < len; i++) { //枚举第一串长度大于3的字串。
for(int j = i + 2; j < len; j++) {
strncpy(s1, str[0]+i, j - i + 1); //截取str[0]中i 到j-i + 1 这一段的字符;
s1[j-i + 1] = '\0'; //需要手动加上'\0'结束符。
// printf("%s\n", s1);
int flag = 1;
for(int k = 1; k < m&&flag; k++) {
if(strstr(str[k], s1) == NULL) { //用该字串和其它串进行匹配。
flag = 0;
}
}
// printf("%d\n", flag);
if(flag) {
if(t == 0) {
strcpy(ans, s1);
t++;
}else {
int ans1 = strlen(ans);
int slen = strlen(s1);
if(ans1 < slen) {
strcpy(ans, s1);
}else if(ans1 == slen && strcmp(ans, s1) > 0) {
strcpy(ans, s1);
}
}
}
}
}
if(t != 0) {
printf("%s\n", ans);
}else {
printf("no significant commonalities\n");
}
}
return 0;
}
hdu1671 字典树
/*
2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
*/
//题意给出机组单词, 如果不存在一个单词是另一个单词的前缀,输出YES or 输出NO;
#include <string>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
struct node
{
bool end;
int a[10];
};
bool x;
int ptr;
node list[100000];
void Init()
{
x=true;
ptr=0;
for(int i=0;i<100000;i++)
{
list[i].end=false;
for(int j=0;j<10;j++)
list[i].a[j]=-1;
}
}
void Insert(char*s)
{
bool z=false;
bool y=false;
int now=0;
int len=strlen(s);
for(int i=0;i<len;i++)
{
if(list[now].a[s[i]-'0']==-1)
{
z=true;
list[now].a[s[i]-'0']=++ptr;
now=ptr;
}
else
{
now=list[now].a[s[i]-'0'];
if(list[now].end) y=true;
}
}
list[now].end=true;
x=(!y)&&z;
}
int main()
{
int t,n;
char s[11];
scanf("%d",&t);
while(t--)
{
Init();
scanf("%d",&n);
while(n--)
{
scanf("%s",&s);
if(x) Insert(s);
}
if(x) printf("YES\n");
else printf("NO\n");
}
return 0;
}
hdu1671 字典树 入门
最新推荐文章于 2019-12-02 19:49:42 发布