字符串相关算法合集

...日后会慢慢补(flag!)先来讲讲基本的

一.字符串Hash

将字符串用一个数表示,常用的写法有:

1.自然溢出

2.单Hash

3.双Hash

前两个会被精心构造的串卡掉,最后一个虽然目前卡不掉,但是出题人可以卡你常数。

所以这个算法很Naive?不是的

我们来看一道题 bzoj1014

用splay维护字符串的最长公共前缀,那么问题来了,没有一种OI比赛中常用的数据结构能维护一个动态的字符串

这时字符串哈希就派上了用场

我们用一个哈希值来表示字符串

在splay上跑一个二分查找就好了

具体的Hash方法网上都有

这里仅介绍思想

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define ll unsigned long long
#define pi 3.14
#define eps 1e-9
#define inf 2147483233
#define m(a) memset(a,0,sizeof(a))
#define M(a) memset(a,127,sizeof(a))
#define REP(i,m,n) for(int i=1;i<=n;i++)
#define DWN(i,n,m) for(int i=n;i>=1;i++)
#define lowbit(x) x&(-x)
#define POJ(n) while(~scanf("%d",&n) && n)
using namespace std;
int n;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch)){x=10*x+ch-‘0‘;ch=getchar();}
    return x*f;
}
inline void write(int x)
{
    int num=0;
    char buf[15];
    while(x)buf[++num]=(x%10)+‘0‘,x/=10;
    while(num)putchar(buf[num--]);
    putchar(‘\n‘);
}
ll powe[150000];
void makepow()
{
    int i;
    for(powe[0]=1,i=1;i<140142;i++)powe[i]=powe[i-1]*131;
}
const int maxn=140142;
char str[maxn];
struct SplayTree
{
    int rt,Size;
    int son[maxn][2],f[maxn],size[maxn];
    ll val[maxn],hsh[maxn];
    char s[maxn];
    inline void pushup(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;hsh[x]=hsh[son[x][0]]+powe[size[son[x][0]]]*s[x]+powe[size[son[x][0]]+1]*hsh[son[x][1]];}
    inline void Rotate(int x,int type)
    {
        int y=f[x];
        son[y][!type]=son[x][type];
        f[son[x][type]]=y;
        f[x]=f[y];
        if(f[x])son[f[y]][son[f[y]][1]==y]=x;
        son[x][type]=y;
        f[y]=x;
        size[x]=size[y],hsh[x]=hsh[y];
        pushup(y);
    }
    inline void splay(int x,int goal)
    {
        while(f[x]!=goal)
        {
            if(f[f[x]]==goal)
            {
                if(son[f[x]][0]==x)Rotate(x,1);
                else Rotate(x,0);
            }
            else
            {
               int y=f[x],z=f[y];
               if(son[z][0]==y)
               {
                  if(son[y][0]==x)Rotate(y,1),Rotate(x,1);
                  else Rotate(x,0),Rotate(x,1);
               }
               else
               {
                   if(son[y][1]==x)Rotate(y,0),Rotate(x,0);
                   else Rotate(x,1),Rotate(x,0);
               }
            }
        }
        if(goal==0) rt=x;
    }
    inline int rank(int x,int k)
    {
        if(k<=size[son[x][0]]) return rank(son[x][0],k);
        else if(k==size[son[x][0]]+1) return x;
        else return rank(son[x][1],k-size[son[x][0]]-1);
    }
    inline int build(int l,int r,int id)
    {
        if(l>r)return 0;
        int x=++Size,mid=(l+r)>>1;
        f[x]=id;
        s[x]=str[mid];
        son[x][0]=build(l,mid-1,x);
        son[x][1]=build(mid+1,r,x);
        pushup(x);
        return x;
    }
    inline void insert(int k,char val)
    {
        int x=rank(rt,k),y=rank(rt,k+1);
        splay(x,0),splay(y,x);
        s[++Size]=val;
        f[Size]=y,son[y][0]=Size;
        pushup(Size);
        pushup(y);
        pushup(x);
    }
    inline void change(int k,int val)
    {
        int x=rank(rt,k);
        splay(x,0);
        s[x]=val;
        pushup(x);
    }
    inline int bisearch(int kx,int ky)
    {
        int l=0,r=n,mid;
        while(l<=r)
        {
            mid=l+r>>1;
            if(ky+mid>n+2)
            {
                r=mid-1;
                continue;
            }
            int x=rank(rt,kx-1),y=rank(rt,kx+mid);
            splay(x,0),splay(y,x);
            ll temp=hsh[son[y][0]];
            x=rank(rt,ky-1),y=rank(rt,ky+mid);
            splay(x,0),splay(y,x);
            if(temp==hsh[son[y][0]])l=mid+1;
            else r=mid-1;
        }
        return r;
    }
}splay;
int main()
{
    int m,i,j,k,x,y;
    char op[10],val[10];
    scanf("%s%d",str+1,&m);
    makepow();
    n=strlen(str+1);
    splay.rt=splay.build(0,n+1,0);
    for(i=1;i<=m;i++)
    {
        scanf("%s",op);
        if(op[0]==‘I‘)
        {
            scanf("%d%s",&x,val);
            splay.insert(x+1,val[0]);
            n++;
        }
        else if(op[0]==‘R‘)
        {
            scanf("%d%s",&x,val);
            splay.change(x+1,val[0]);
        }
        else
        {
            scanf("%d%d",&x,&y);
            if(x>y)  swap(x,y);
            if(x!=y)
                printf("%d\n",splay.bisearch(x+1,y+1));
            else
                printf("%d\n",n-x+1);
        }
    }
    return 0;
}

bzoj1014

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
const int N = 2e6 + 5;
const int seed = 131;
int mod[2] = {1000000007, 1000000009};
char S[N]; //输入字符串
int F[2][N]; //seed ^ a
int pre[2][N];
int n, g, w;
int tim, vis[N], ans[N];
map <pii, int> cnt;

void pre_init(){ //deal with seed ^ n
    for(int t = 0; t <= 1; t++){
        F[t][0] = 1;
        for(int i = 1; i < N; i++){
            F[t][i] = (LL)F[t][i-1] * seed % mod[t];
        }
    }
}

pii Hash(string s){ //Hash a string
    int ret[2] = {0};
    int len = s.size();
    for(int t = 0; t <= 1; t++){
        for(int i = 0; i < len; i++){
            ret[t] = ((LL) ret[t] * seed + s[i]) % mod[t];
        }
    }
    return pii(ret[0], ret[1]);
}

pii Hash(int l, int r)
{
    int ret[2];
    for(int t = 0; t <= 1; t++){
        ret[t] = (pre[t][r] - (LL)pre[t][l-1] * F[t][r-l+1] % mod[t] + mod[t]) % mod[t];
    }
    return pii(ret[0], ret[1]);
}

void pre_solve(){
    int len = strlen(S + 1);
    for(int t = 0; t <= 1; t++){
        pre[t][0] = 0;
        for(int i = 1; i <= len; i++){
            pre[t][i] = ((LL)pre[t][i-1] * seed + S[i]) % mod[t];
        }
        for(int j = len + 1, i = 1; i <= w - 1; i++, j++){
            pre[t][j] = ((LL)pre[t][j-1] * seed + S[i]) % mod[t];
        }
    }
}

bool check(int id){
    tim++;
    int l = id, r = id + w - 1;
    for(int i = 1; i <= n; i++, l += w, r += w){
        pii t = Hash(l, r);
        if(!cnt.count(t)) return 0; //目标串中没有这个子串
        int p = cnt[t];
        if(vis[p] == tim) return 0; //目标串出现了大于1次
        vis[p] = tim; ans[i] = p;
    }
    printf("YES\n");
    for(int i = 1; i <= n; i++) cout << ans[i] <<" "; cout << endl;
    return 1;
}

int main()
{
    pre_init();
    scanf("%d%d%s", &n, &w, S+1);
    pre_solve();
    scanf("%d", &g);
    for(int i = 1; i <= g; i++){
        scanf("%s", S);
        pii t = Hash(S);
        cnt[t] = i;
    }
    bool mark = 0;
    for(int i = 1; i <= w; i++){
        if(check(i)){
            mark = 1;
            break;
        }
    }
    if(mark == 0){
        printf("NO\n");
    }
    return 0;
}

双哈希代码(源网)

模数之一要用19260817这个大质数

有奇效

二.K(kan)M(mao)P(pian)

一类用于单字符串匹配的O(n+m)的算法

解释也不是很好讲

直接上模板吧

#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int p[101];
int main()
{
    string a,b;
    cin>>a>>b;
    int n=a.length(),m=b.length();
    a=" "+a;b=" "+b;
    int j=0;
    for(int i=2;i<=m;i++)
    {
            while(j>0&&b[j+1]!=b[i])j=p[j];
            if(b[j+1]==b[i])j++;
            p[i]=j;
            }
    j=0;
    for(int i=1;i<=n;i++)
    {
            while(j>0&&b[j+1]!=a[i])j=p[j];
            if(b[j+1]==a[i])j++;
            if(j==m){printf("%d",i-m+1);break;}
            }
    return 0;
}

三.AC自动机

/*多么希望AC和自动能够换一下*/

就是在Trie树上跑KMP

每个点都有一个Fail指针表示如果这个点匹配不上跳到哪个地方

四.字符串dp

1.O(n^2)可以过的dp

设计状态一般至少为dp[i][j]表示第一个串的前i个和第二个串的前j个怎么这么样

2.AC自动机上的dp

两种做法:第一个是构建Fail树,跑树形dp

另外一种不能在Fail树上做的,一般有一维表示"当前在AC自动机的x号节点上"

原文地址:https://www.cnblogs.com/Kong-Ruo/p/8127695.html

时间: 2024-10-12 10:58:00

字符串相关算法合集的相关文章

原生 JS 中对象相关 API 合集

https://juejin.im/entry/58f8a705a0bb9f0065a4cb20 原文链接:https://microzz.com/2017/04/20/jsobject/ 原生 JavaScript 中对象相关 API 合集 - 对象篇.现在 jQuery 已经没有那么有优势了,原生 JS 赶紧学起来... -- 由microzz分享 Microzz [email protected] 主页 文章 标签 GitHub 关于我 掘金专栏 SegmentFault Vue音乐播放器

Java相关配置合集

Java环境变量配置: 1.安装JDK,安装过程中可以自定义安装目录等信息,例如我们选择安装目录为C:\java\jdk1.6.0_08: 2.安装完成后,右击“我的电脑”,点击“属性”: 3.XP选择[高级]选项卡,WIN7选择[高级系统设置] ,然后点击“环境变量”: 4.在“系统变量”中新建变量名为:JAVA_HOME,变量值为:指明JDK安装路径,就是刚才安装时所选择的路径 C:\java\jdk1.6.0_08: 点确定 5.在“系统变量”找到path这个变量,选中后点编辑,鼠标放在变

.Net 2014 Connect() 相关文章合集

微软在11月中旬的Connect()研讨会中公布了一系列 2015年的发展规划,今天在MSDN Blog上看到了一篇比较全的相关文章合集,这里转录一下,感兴趣的朋友可以看看. Announcements Opening up Visual Studio and .NET to Every Developer, Any Application: .NET Server Core open source and cross platform, Visual Studio Community 2013

前端相关网址合集

综合类 | 地址--- | --- 前端知识体系--http://www.cnblogs.com/sb19871023/p/3894452.html前端知识结构--https://github.com/JacksonTian/fks免费的编程中文书籍索引--https://github.com/justjavac/free-programming-books-zh_CN智能社 - 精通JavaScript开发--http://study.163.com/course/introduction/2

2017下半年8场云计算相关会议合集 聚焦大数据未来!

随着云计算服务在各行各业的应用热度递增,云计算产业蓬勃发展.各种行业会议也应运而生.活动家就给大家盘点下2017年下半年8场云计算相关会议 聚焦大数据未来!哪些大数据相关的最新行业会议是值得参加的! 注:为了方便阅读,会议以时间由近到远排序. 一.BDFF 2017大数据金融论坛 活动主题 塑造数据生态·引领金融科技·聚焦数据未来 Shape Data Ecology·Lead Fintech·Focus on Data Future 活动日期.地点.网址 2017年8月23-24日 上海 20

原生JS中DOM节点相关API合集

节点属性 Node.nodeName //返回节点名称,只读 Node.nodeType //返回节点类型的常数值,只读 Node.nodeValue //返回Text或Comment节点的文本值,只读 Node.textContent //返回当前节点和它的所有后代节点的文本内容,可读写 Node.baseURI //返回当前网页的绝对路径 Node.ownerDocument //返回当前节点所在的顶层文档对象,即document Node.nextSibling //返回紧跟在当前节点后面

[算法整理]树上求LCA算法合集

1#树上倍增 以前写的博客:http://www.cnblogs.com/yyf0309/p/5972701.html 预处理时间复杂度O(nlog2n),查询O(log2n),也不算难写. 2#st表(RMQ) 首先对一棵树进行dfs,得到欧拉序列,记录下每个节点的第一次出现位置. (先序遍历这棵树,访问到的节点(无论是从深的一层返回还是父节点访问)就加入到序列中,序列长度为2 * n - 1) 根据欧拉序列神奇的特性,两个点第一次出现的位置之间,深度最小的一个点,是这两个点LCA(反正我是不

PHP中自带的字符串操作函数合集

1.查找字符位置函数: strpos($str,search,[int])://查找search在$str中的第一次位置从int开始: strrpos($str,search,[int])://查找search在$str中的最后一次出现的位置从int开始 2.提取子字符函数(双字节) submit($str,int start[,int length])://从$str中strat位置开始提取[length长度的字符串]. strstr($str1,$str2)://从$str1(第一个的位置)

原生JS中对象相关API合集

Object对象 生成实例对象 var o = new Object() 属性 Object.prototype //返回原型对象 方法 Object.keys(o) //遍历对象的可枚举属性 Object.getOwnPropertyName(o) //遍历对象不可枚举的属性 对象实例的方法 valueOf // 返回当前对象对应的值. toString // 返回当前对象对应的字符串形式. toLocaleString // 返回当前对象对应的本地字符串形式. hasOwnProperty