首页 > 代码库 > 字符串hash - 简单的字符匹配 --- poj 3461
字符串hash - 简单的字符匹配 --- poj 3461
Oulipo
Problem‘s Link:http://poj.org/problem?id=3461
Mean:
给你一个模式串P和一个母串S,让你统计P串在S串中出现的次数。
analyse:
这题我一开始想到的就是使用KMP,就用KMP写了,93ms,挺快的。我又用AC自动机写了一遍(纯属娱乐),万万没想到竟然超时了,是我姿势不对么?
后来看别人有用字符串hash写的,听说字符串hash在某些问题中比AC自动机什么的厉害多了,于是又用字符串hash写了一遍,确实挺不错的,代码30+行,而且速度也挺快,173ms。要好好搞一下字符串hash,这个确实是一个好东西,听说字符串hash熟练了以后根本不用其他AC自动机、后缀数组就可以解决很多问题了。
在字符串hash中又学到了unsigned long long超范围后会自动对2^64取模,hash的利器啊,省去了手动取模。
Time complexity:O(n*m)
Source code:
字符串hash代码:
#include<stdio.h>#include<string.h>#define ULL unsigned long longint seed=100;char s1[10005],s2[1000005];int main(){ int t; scanf("%d",&t); while(t--) { scanf("%s%s",s1,s2); int len1=strlen(s1),len2=strlen(s2); ULL a1=0,a2=0,l1=1; for(int i=0;i<len1;++i) { a1=a1*seed+(s1[i]-‘A‘+1); l1*=seed; } for(int i=0;i<len1;++i) { a2=a2*seed+(s2[i]-‘A‘+1); } int ans=0; if(a1==a2) ans++; for(int i=len1;i<len2;++i) { a2=a2*seed+(s2[i]-‘A‘+1)-l1*(s2[i-len1]-‘A‘+1); if(a2==a1) ans++; } printf("%d\n",ans); } return 0;}
KMP代码:
// Memory Time// 1347K 0MS// by : Snarl_jsb// 2014-10-04-11.53#include<algorithm>#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<vector>#include<queue>#include<stack>#include<map>#include<string>#include<climits>#include<cmath>#define N 1000010#define LL long longusing namespace std;char s1[10005],s2[1000005];vector<int> next;void GetNext(char s[]){ int len=strlen(s),k=0; next.clear(); next.push_back(0); for(int i=1;i<len;++i) { while(k!=0&&s[i]!=s[k]) k=next[k-1]; if(s[i]==s[k]) k++; next.push_back(k); }}int KMP(char s1[],char s2[]){ int l1=strlen(s1),l2=strlen(s2); int k=0,ans=0;; for(int i=0;i<l2;++i) { while(k!=0&&s2[i]!=s1[k]) k=next[k-1]; if(s2[i]==s1[k]) k++; if(k==l1) { ans++; k=next[k-1]; } } return ans;}int main(){ int t; scanf("%d",&t); while(t--) { scanf("%s%s",s1,s2); int len1=strlen(s1),len2=strlen(s2); GetNext(s1); printf("%d\n",KMP(s1,s2)); } return 0;}
AC自动机超时代码(求大牛指针QAQ):
// Memory Time// 1347K 0MS// by : Snarl_jsb// 2014-09-30-11.01#include<algorithm>#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<vector>#include<queue>#include<stack>#include<map>#include<string>#include<climits>#include<cmath>#define LL long longusing namespace std;const int N = 1001000;char str[N];struct node{ node *next[30]; // 每个结点都对应30个字母的指针 node *fail; // 失配指针 int count; // node() // 构造函数初始化 { for(int i = 0; i < 30; i++) next[i] = NULL; count = 0; fail = NULL; }}*q[N];node *root;int head, tail;void Insert(char *str) // 插入单词.相当于构建一个Trie树{ node *p = root; int i = 0, index; while(str[i]) { index = str[i] - 65; // 转化为相对数字来存 if(p->next[index] == NULL) // 该字母未插入过 p->next[index] = new node(); // 为该字母申请一个结点 p = p->next[index]; // 移至下一个 i++; } p->count++; // 记录该结点的单词总共插入的次数}void build_ac_automation(node *root) // bfs建立fail指针{ root->fail = NULL; q[tail++] = root; while(head < tail) { node *temp = q[head++]; node *p = NULL; for(int i = 0; i < 30; i++) { if(temp->next[i] != NULL) { if(temp == root) temp->next[i]->fail = root; else { p = temp->fail; while(p != NULL) { if(p->next[i] != NULL) { temp->next[i]->fail = p->next[i]; break; } p = p->fail; } if(p == NULL) temp->next[i]->fail = root; } q[tail++] = temp->next[i]; } } }}int total=0;int Query(node *root) // 匹配 + 统计{ int i = 0, cnt = 0, index; node *p = root; int idx=0; while(str[i]) { index = str[i] - 65; while(p->next[index] == NULL && p != root) //前缀是相同的,所以不管哪个指针走到了count不为0的结点上,那么该结点所代表的单词就匹配成功 p = p->fail;//失配情况下,p指针指向p->fail.(相当于KMP的next数组) p = p->next[index];//由于现在所在的位置是父节点,所以需要向下移动一个位置 if(p == NULL) p = root; //如果匹配失败,移动到root,重新开始匹配 node *temp = p;// while(temp != root && temp->count != -1) //统计--如果匹配成功,那么count>1,表示该结点代表的单词数量;否则表示该结点没有单词 { if(temp->count>0) { cnt ++; //统计该单词出现的次数 }// temp->count = -1; //标记为-1,表示该单词已经加入了cnt中,下次就不用重复统计 temp = temp->fail;//判断整条链上的匹配情况 } i++; } return cnt;}int main(){ int t; cin>>t; while(t--) { head=tail=0; root=new node(); scanf("%s",str); Insert(str); build_ac_automation(root); scanf("%s",str);// Query(root); printf("%d\n",Query(root)); } return 0;}
字符串hash - 简单的字符匹配 --- poj 3461
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。