ACM中常用算法----字符串

本文详细介绍了ACM竞赛中常用的字符串算法,包括Hash、字典树、KMP、AC自动机、Manacher、后缀数组、EX_KMP和SAM后缀自动机,并提供了相关例题。
摘要由CSDN通过智能技术生成

ACM中常用算法—-字符串

ACM中常用的字符串算法不多,主要有以下几种:

  1. Hash
  2. 字典树
  3. KMP
  4. AC自动机
  5. manacher
  6. 后缀数组
  7. EX_KMP
  8. SAM(后缀自动机)
  9. 回文串自动机

下面来分别介绍一下:

0. Hash

字符串的hash是最简单也最常用的算法,通过某种hash函数将不同的字符串分别对应到不同的数字.进而配合其他数据结构或STL可以做到判重,统计,查询等操作.

  • #### 字符串的hash函数:

一个很简单的hash函数代码如下:


ull xp[maxn],hash[maxn];

void init()
{
    xp[0]=1;
    for(int i=1;i<maxn;i++)
        xp[i]=xp[i-1]*175;
}

ull get_hash(int i,int L)
{
    return hash[i]-hash[i+L]*xp[L];
}

scanf("%s",str);
int n=strlen(str);
hash[n]=0;
for(int i=n-1;i>=0;i--)
{
    hash[i]=hash[i+1]*175+(str[i]-'a'+1);
}

其中175是顺便选择的基数,对一个串通过init的预处理后,就用get_hash(i,L)可以得到从位置i开始的,长度为L的子串的hash值.

一般情况下,这个简单的hash函数已经足够好了.但使用hash函数解题的时候还是有问题要注意:

  1. hash函数的结果并不一定准确,hash的值可能会有冲突导致结果错误(但不常遇到可以换hash数即可).

  2. 对于一般的字符串,这个hash函数准确性很高. 但是有的题目会刻意构造可以使hash函数失效的字符串,无论换什么样的hash数都过不了,这时就需要对hash函数进行修改,不能使用自然溢出的方式储存hash值,可以选取两个大质数,对用一个字符串记录它的hash值和这两个数的mod.用这种方法可以过掉几乎全部卡hash函数的题

例题
  • HDOJ 4821 String
  • HDOJ 4080 Stammering Aliens
  • HDOJ 4622 Reincarnation
  • CSU1647: SimplePalindromicTree

1. 字典树

字典树是储存着不同字符串的数据结构,是一个n叉树(n为字符集的大小),对于一棵储存26个字母的字典树来说,它的的每一个节点储存着26个指针可以分别代表这个节点的后面加上’a’~’z’后可以指向那个节点.

插入的时候从根节点开始,沿着对应的边走(如果某个指针后面指向的节点为空.可以新建一个节点),走到字符串结束的时候在当前停留的节点标记一下(是否出现过,出现了几次等).

查询的时候也是一样从根节点走,如果走到某个节点无路可走了,说明查不到.当一路走到字符串结束时,检查当前停留的节点是否被标记过.

一份代码参考:

/*字典树*/

const int CHAR=26,MAXN=100000;

struct Trie
{
    int tot,root,child[MAXN][CHAR];
    bool flag[MAXN];

    Trie()
    {
        memset(child[1],0,sizeof(child[1]));
        flag[1]=true;
        root=tot=1;
    }

    void Insert(const char *str)
    {
        int *cur=&root;
        for(const char*p=str;*p;p++)
        {
            cur=&child[*cur][*p-'a'];
            if(*cur==0)
            {
                *cur=++tot;
                memset(child[tot],0,sizeof(child[tot]));
                flag[tot]=false;
            }
        }

        flag[*cur]=true;
    }

    bool Query(const char *str)
    {
        int *cur=&root;
        for(const char *p=str;*p&&*cur;p++)
            cur=&child[*cur][*p-'a'];
        return (*cur)&&flag[*cur];
    }

}tree;
例题
  • POJ 3630 Phone List
  • HDOJ 4622 Reincarnation
  • HDOJ 1251 统计难题

2. KMP

kmp是一种字符串匹配的算法,普通的字符串匹配需要时间O(n*m) n:字符串长度 m:模版串长度,kmp算法通过对模版串进行预处理来找到每个位置的后缀和第一个字母的前缀的最大公共长度,可以让复制度降低到O(n+m)

关于KMP算法白书有很详细的介绍,网上也有很多.

KMP资料1 , KMP资料2

一种实现:


char t[1000],p[1000];
int f[1000];

void getfail(char* p,int* f)
{
    int m=strlen(p);
    f[0]=f[1]=0;
    for(int i=1;i<m;i++)
    {
        int j=f[i];
        w
  • 17
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值