最近打算把hihocoder上之前的都补一下,会的就当做复习,不会的要抓紧学习。
感觉基础算法还有好多漏洞。 要加紧脚步了。
掌握这两个之后就可以学习trie图了(感觉ac自动机算是他的一种构造DFA的方法?)
KMP:
资料:http://blog.csdn.net/v_july_v/article/details/7041827
讲的比我详细。。 我就是简单总结下。
用于字符串的匹配问题,对于普通的做法需要O(n*m)的复杂度暴力匹配,一旦失配需要从这一次原串匹配的开头字符的下一个字符开始匹配,也就是意味着原串所正在匹配的位置 i 可能会一直回退。
KMP复杂度O(m+n),KMP的做法就是保证了指向原串正在匹配的位置的i不会回退,这里就用到了一个next数组,这个数组是针对模式串的,意思就在于如果当前字符失配的模式串的下标应该指向哪里可以保证在这个之前的跟原串的是相匹配的。
然而求next数组其实也就是模式串跟自身的匹配,对于每一个下标i,找出最长的p[0~k] 和 p[i-k ~ i] 这个k最大是多少,然后把这个想法改造一下,改成对于每一个字符失配的时候应该跳转到哪里跟原串的当前字符继续匹配,对于每一个i取 i-1的那个最大的k+1了。把next[0]设为-1。很容易求出next 数组。
hihocoder week3
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 10000009
char s[M],p[M];
int nextval[M];
int t;
void getnextval()
{
int i = 0,j = -1;
int l = strlen(p);
nextval[0] = -1;
while(i < l)
{
if(j == -1 || p[i] == p[j])
{
i++;
j++;
if(p[i] != p[j]) nextval[i] = j;
else nextval[i] = nextval[j]; //如果字符相同就递归回去保证不会回退到字符相同的地方
}
else j = nextval[j];
}
}
int search(char* s,char*p)
{
int i = 0,j = 0;
int slen = strlen(s);
int plen = strlen(p);
int sum = 0;
while(i < slen && j < plen)
{
if(j == -1 || s[i] == p[j])
{
i++;
j++;
if(j == plen)
{
sum++;
j = nextval[j];
}
}
else j = nextval[j];
}
return sum;
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(nextval,0,sizeof(nextval));
scanf("%s%s",p,s);
getnextval();
printf("%d\n",search(s,p));
}
return 0;
}
trie树:
字典树,这个也比较简单。可以用来统计相同的前缀出现过几次。
学习资料:http://dongxicheng.org/structure/trietree/
定义节点,每个节点都代表了一个字母(根节点除外),每个节点包含两个信息:1)从根节点走到当前节点的这个字符串作为前缀出现过了几次。2)在这个节点上挂一个数组,对应的下标就是儿子所表示的字母。
两种操作:
1)插入字符串:从根节点开始沿着这个字符串走,如果这个节点还没被创建就new一个,如果已经有了在计数处+1
2)查询:也是从根节点开始沿着要查询的那个字符串走,如果这个节点没有那么就是这样的前缀一次都没有出现过,否则走完返回那个节点计数的值。
比较简单,上代码
hihocoder week2
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define M 100009
#define maxn 26
typedef struct tire
{
int tcount;
tire* next[maxn];
};
int n,m;
tire* create()
{
tire* tmp = new tire;
tmp->tcount = 1;
for(int i = 0;i < maxn;i++)
tmp->next[i] = NULL;
return tmp;
}
void insert(tire* root,char* ch)
{
tire* tmp = root;
int l = strlen(ch);
for(int i = 0;i < l;i++)
{
int k = ch[i] - 'a';
if(tmp->next[k]) tmp->next[k]->tcount++;
else tmp->next[k] = create();
tmp = tmp->next[k];
}
}
int search(tire* root,char* ch)
{
if(root == NULL) return 0;
tire* tmp = root;
int l = strlen(ch);
for(int i = 0;i < l;i++)
{
int k = ch[i] -'a';
if(tmp->next[k]) tmp = tmp->next[k];
else return 0;
}
return tmp->tcount;
}
int main()
{
while(scanf("%d",&n) == 1)
{
tire* root = new tire;
for(int i = 0;i < n;i++)
{
char s[100];
scanf("%s",s);
insert(root,s);
}
scanf("%d",&m);
for(int i = 0;i < m;i++)
{
char s[100];
scanf("%s",s);
printf("%d\n",search(root,s));
}
}
return 0;
}