字符串系列复习

AC自动机

Trie+Fail指针,通常配合动归出现在比较明显的字符串题中。

几个注意点:

1.bfs建图时先将所有fail指针指向根(0号节点),一开始应将根的所有儿子放入队列而不是根本身。

2.模板使用的方法是建立trie图而不是树,注意处理。

3.fail指针构成一棵树(显然),解题时常利用这个性质。

4.直接按照trie的方法建树,然后按bfs序建图。

5.常用于多串匹配,技巧是现考虑暴力再考虑用自动机性质优化复杂度。

void ins(char s[]){
    int l=strlen(s),x=0;
    rep(i,0,l-1){
        int t=s[i]-‘A‘+1;
        if (!ch[x][t]) clear(++cnt),ch[x][t]=cnt;
        x=ch[x][t];
    }
    w[x]=1;
}

void build(){
    int st=1,ed=0;
    rep(i,1,26) if (ch[0][i]) q[++ed]=ch[0][i];
    while (st!=ed+1){
        int x=q[st++];
        rep(i,1,26)
            if (ch[x][i]) q[++ed]=ch[x][i],fail[ch[x][i]]=ch[fail[x]][i];
                        else ch[x][i]=ch[fail[x]][i];
        w[x]|=w[fail[x]];
    }
}

后缀自动机

http://blog.csdn.net/doyouseeman/article/details/52245413

与后缀树有关联,暂时不会。

相当于将一个串的所有后缀放入一个trie然后将几个出现位置(右断点)相同的串压缩到同一个节点

稍难理解,注意点:

1.之所以能处理子串问题,本质是利用了“子串就是某个后缀的前缀”

2.一个节点存储几个Right集合相同的串(一定互为后缀),但也可以认为它只表示一个串(从根走到这个节点就相当于只走到这一个串上)

3.x代表的所有串后接一个c之后的Right集合与son[x][c]Right集合完全相同,而fa[x]代表的集合包含x代表的集合(且是最小的包含x代表的集合的节点)。

4.从根发出所有路径构成了原串的所有子串。每个节点代表子串的长度范围是(  mx[fa[x]]  ,  mx[x]  ]。

5.走son寻找子串,走fa传递信息。两节点代表的集合若非包含关系则必然不相交。

主要应用于大量子串处理问题上,也可配合map等骗分。

void ext(int c){
     int p=lst,np=lst=++cnt; mx[np]=mx[p]+1;
     l[np]=r[np]=mx[np];
     while (!son[p][c] && p) son[p][c]=np,p=fa[p];
     if (!p) fa[np]=1;
     else{
          int q=son[p][c];
          if (mx[p]+1==mx[q]) fa[np]=q;
          else{
               int nq=++cnt; mx[nq]=mx[p]+1;
               memcpy(son[nq],son[q],sizeof(son[q]));
               fa[nq]=fa[q]; fa[np]=fa[q]=nq;
               while (son[p][c]==q) son[p][c]=nq,p=fa[p];
          }
     }
}

广义后缀自动机,多个串放入同一个SAM,每次lst赋值为根,暂不熟练。

https://www.cnblogs.com/candy99/p/sam.html

后缀数组

应用范围比后缀自动机广,但模板很容易忘记,常配合height解题。

http://www.cnblogs.com/candy99/p/6666617.html

http://wenku.baidu.com/link?url=Beh6Asxvtm7M2QY5kiPyKKaP87xvBrNBKW9LXOeGKm-WM4GoUM3opnHZ8z-DahF7TRaLZZ4cpUe6jfFF064XUEmAiIDF7t90CpgNfSC3_Pq

注意:模板背熟,有时可以配合并查集使用,常用二分和按照height数组大小分组的方法。

struct sa_array{
   int sa[N],rk[N],h[N],st[N][16],x[N],y[N],c[N]; char S[N];
   int Cmp(int a,int b,int l){ return y[a]==y[b] && y[a+l]==y[b+l]; }

   void build_sa(int m){
      memset(y,0,sizeof(y));
      rep(i,0,m) c[i]=0;
      rep(i,1,n) c[x[i]=S[i]-‘a‘+1]++;
      rep(i,1,m) c[i]+=c[i-1];
      for (int i=n; i; i--) sa[c[x[i]]--]=i;
      for (int k=1,p=0; p<n; k<<=1,m=p){
         p=0;
         rep(i,n-k+1,n) y[++p]=i;
         rep(i,1,n) if (sa[i]>k) y[++p]=sa[i]-k;
         rep(i,0,m) c[i]=0;
         rep(i,1,n) c[x[y[i]]]++;
         rep(i,1,m) c[i]+=c[i-1];
         for (int i=n; i; i--) sa[c[x[y[i]]]--]=y[i];
         rep(i,1,n) y[i]=x[i]; p=1; x[sa[1]]=1;
         rep(i,2,n) x[sa[i]]=Cmp(sa[i-1],sa[i],k) ? p : ++p;
      }
   }

   void get(){
       int k=0;
      rep(i,1,n) rk[sa[i]]=i;
      rep(i,1,n){
         for (int j=sa[rk[i]-1]; i+k<=n && j+k<=n && S[i+k]==S[j+k]; k++);
         h[rk[i]]=k; if (k) k--;
      }
   }

   void rmq(){
      rep(i,1,n) st[i][0]=h[i];
      rep(i,1,log[n])
      rep(j,1,n-(1<<i)+1) st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
   }

   int ask(int l,int r){
      l++; int t=log[r-l+1];
      return min(st[l][t],st[r-(1<<t)+1][t]);
   }

   int que(int x,int y){ return ask(min(rk[x],rk[y]),max(rk[x],rk[y]));}

}SA;

KMP,Manacher较好理解,暂略。

扩展KMP一般可以用前述数据结构代替,还不会。

想不到用这些数据结构维护?用哈希!

原文地址:https://www.cnblogs.com/HocRiser/p/8178517.html

时间: 2024-10-05 03:09:44

字符串系列复习的相关文章

(原创)Python字符串系列(1)——str对象

在本博客 <Python字符串系列> 中,将介绍以下内容: Python内置的str对象及操作 字符串的格式化 Python中的Unicode字符串 Python中的正则表达式 re模块 本文将介绍Python内置的 str 类型,列举Python中字符串对象支持的方法,使用这些方法可以实现强大的字符串处理功能. 在Python 2 中,普通字符串与Unicode字符串有着明确的区分,二者都是Python内置的基本类型,例如: >>> type(str) <type '

字符串系列函数(不断跟新)

1.sprintf,sprintf_s sprintf(char* buffer, const char* format, [argument]); vs下需要加上_CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; int main() { char name[1]; int input = 9099; sprintf(name,"%d", input); system("pause&q

字符串系列0

基本的字符串操作 (如上图) 我会将每个函数的操作实现记录在本系列中, 因为发现网上都是单一的某些实现,每个函数可能不止一种实现 慢慢更新...... ----------------------------------------------------- Writed by Zoro /April /15th /2019 原文地址:https://www.cnblogs.com/xuzhaoping/p/10713795.html

字符串的复习

IsNullOrEmpty 判断字符串是否为null或者空 static void Main(string[] args) { string s1 = "张三"; if(string.IsNullOrEmpty(s1)) { Console.WriteLine("是的"); } else { Console.WriteLine("不是"); } Console.ReadKey(); } IsNullOrEmpty

leetcode字符串系列

3. 无重复字符的最长子串 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3. 示例 2: 输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1. 示例 3: 输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串

LeetCode --- 字符串系列 --- 机器人能否返回原点

机器人能否返回原点 小注释:都说算法题刷的多了,越做越熟练,因为差不多都是那几个套路 今天碰到这个题目,有点感触.很快就解出来了,虽然是简单题. 做这题之前,遇到的是分割平衡字符串 有点类似,所以能很快解出下面这道题 题目 在二维平面上,有一个机器人从原点 (0, 0) 开始. 给出它的移动顺序,判断这个机器人在完成移动后是否在?(0, 0) 处结束. 移动顺序由字符串表示.字符 move[i] 表示其第 i 次移动. 机器人的有效动作有?R(右),L(左),U(上)和 D(下). 如果机器人在

LeetCode --- 字符串系列 --- 特殊等价字符串组

特殊等价字符串组 注释:这道题目题意太过难理解,理解题意花了几小时... 下面将对题目进行括号注释.... 题目 你将得到一个字符串数组 A.比如 (["a2cd","ac2d","2acd", "c2ad"]) 如果经过任意次数的移动,S == T,那么两个字符串 S 和 T 是特殊等价的. (比如上面给出的字符串数组,若其中两个数组元素字符串,自身的字符发生任意次数的移动, 移动次数不用相等,最后这两个字符串可以相等,那么

字符串系列函数在序列化中的问题

最近用到了protobuf传输数据,但在protobuf之前还有个协议头. 因为是重构,所以需要模拟协议头部.有如下代码 string data; char buffer[256]; memcpy(buffer, &header, sizeof(header)); data.append(buffer); client端发给server端的数据,总是少几个字节,用gdb调试时,发现有部分截断. 经过定位,发现是buffer序列成为二进制后,有Cstring的终止字符.导致append 不完全.

8.3.4 - mysql 字符串

字符类型 #官网:https://dev.mysql.com/doc/refman/5.7/en/char.html #注意:char和varchar括号内的参数指的都是字符的长度 #char类型:定长,简单粗暴,浪费空间,存取速度快 字符长度范围:0-255(一个中文是一个字符,是utf8编码的3个字节) 存储: 存储char类型的值时,会往右填充空格来满足长度 例如:指定长度为10,存>10个字符则报错,存<10个字符则用空格填充直到凑够10个字符存储 检索: 在检索或者说查询时,查出的结