字符串相关算法模板

最小最大表示法

用途:用于求最小最大的字符串的编号。
模板:

int getMin(char *s)
{
    int i = 0, j = 1, l;
    int len = strlen(s);
    while(i < len && j < len)
    {
        for(l = 0; l < len; l++)
            if(s[(i + l) % len] != s[(j + l) % len])
            	break;
        if(l >= len)
        	break;
        if(s[(i + l) % len] > s[(j + l) % len])
        {
            if(i + l + 1 > j)
            	i = i + l + 1;
            else
            	i = j + 1;
        }
        else if(j + l + 1 > i)
        	j = j + l + 1;
        else
        	j = i + 1;
    }
    return i < j ? i : j;
}
 
int getMax(char *s)
{
    int len = strlen(s);
    int i = 0, j = 1, k = 0;
    while(i < len && j < len && k < len)
    {
        int t = s[(i+k)%len]-s[(j+k)%len];
        if(!t)
        	k++;
        else
        {
            if(t > 0)
            {
                if(j+k+1 > i)
                	j = j+k+1;
                else
                	j = i+1;
            }
            else if(i+k+1 > j)
            	i = i+k+1;
            else
            	i = j+1;
            k = 0;
        }
    }
    return i < j ? i : j;
}

字符串哈希

用途:用于字符串查找,每个字符串都有其对应的值
代码:

			for(int i=0;i<le;++i)
                if(vis[str[i]]==0)
                    vis[str[i]]=cnt++;
            for(int i=0;i<=le-n;++i)
    		{
                int sum=0;
                for(int j=0;j<n;++j)
                    sum=sum*cnt+vis[str[j+i]];
                if(has[sum]==0)
    			{
                    has[sum]=1;
                    ++ans;
                }
            }

KMP

用途:字符串快速匹配。
代码:

void GetNext(string P, int next[])
{
    int p_len = P.size();
    int i = 0;   // P 的下标
    int j = -1;  
    next[0] = -1;

    while (i < p_len - 1)
    {
        if (j == -1 || P[i] == P[j])
        {
            i++;
            j++;
            next[i] = j;
        }
        else
            j = next[j];
    }
}

/* 在 S 中找到 P 第一次出现的位置 */
int KMP(string S, string P, int next[])
{
    GetNext(P, next);
    int i = 0;  // S 的下标
    int j = 0;  // P 的下标
    int s_len = S.size();
    int p_len = P.size();

    while (i < s_len && j < p_len)
    {
        if (j == -1 || S[i] == P[j])  // P 的第一个字符不匹配或 S[i] == P[j]
        {
            i++;
            j++;
        }
        else
            j = next[j];  // 当前字符匹配失败,进行跳转
    }

    if (j == p_len)  // 匹配成功
        return i - j;
    
    return -1;
}

EX-KMP

用途:字符串T 与 字符串S的每一个后缀 的最长公共前缀。
代码:

const int MAX=100010; //字符串长度最大值
int Next[MAX],extend[MAX];

//预处理计算Next数组
void getNext(char str[])
{
    int i=0,j,po,len=strlen(str);
    next[0]=len; //初始化next[0]
    while(str[i]==str[i+1] && i+1<len) i++; next[1]=i; //计算next[1]
    po=1; //初始化po的位置
    for(i=2;i<len;i++)
    {
        if(next[i-po]+i < next[po]+po) //第一种情况,可以直接得到next[i]的值
            next[i]=next[i-po];
        else //第二种情况,要继续匹配才能得到next[i]的值
        {
            j = next[po]+po-i;
            if(j<0) j=0; //如果i>po+next[po],则要从头开始匹配
            while(i+j<len && str[j]==str[j+i]) j++; next[i]=j;
            po=i; //更新po的位置
        }
    }
}

//计算extend数组
void EXKMP(char s1[],char s2[])
{
    int i=0,j,po,len=strlen(s1),l2=strlen(s2);
    getNext(s2); //计算子串的next数组
    while(s1[i]==s2[i] && i<l2 && i<len) i++; extend[0]=i;
    po=0; //初始化po的位置
    for(i=1;i<len;i++)
    {
        if(next[i-po]+i < extend[po]+po) //第一种情况,直接可以得到extend[i]的值
            ex[i]=next[i-po];
        else //第二种情况,要继续匹配才能得到extend[i]的值
        {
            j = extend[po]+po-i;
            if(j<0) j=0; //如果i>extend[po]+po则要从头开始匹配
            while(i+j<len && j<l2 && s1[j+i]==s2[j]) j++; extend[i]=j;
            po=i; //更新po的位置
        }
    }
}

Manacher

用途:求最长回文子串
代码:

int Manacher( string s )
{
	int maxn = 0;
	int po = 0;
	int ans = 0;
	string str = "@#";
	for( int i=0;i<s.size();++i )
	{
		str += s[i];
		str += "#";
	}
	a[0] = 0;
	for( int i=1;i<str.size();++i )
	{
		if ( maxn > i )
			a[i] = min( maxn-i,a[2 * po - i] );
		else
			a[i] = 1;
		while( str[i-a[i]] == str[i+a[i]] )
			++a[i];
		if ( a[i] + i > maxn )
		{
			maxn = a[i] + i;
			po = i;
		}
		ans = max( ans,a[i] );
	}
	return ans-1;
}

字典树

用途:快速查询

struct Trie
{
    int v; 
	Trie *next[26];
	Trie(){
		v=0;
		for(int i=0;i<26;++i)
			next[i] = NULL;
	}
}*root;

void createTrie(string str)
{
	Trie *p = root,*q;
	for(int i=0;i<str.length();++i)
	{
		int id=str[i]-'a';
		if(p->next[id] == NULL)
		{
			q = new Trie();
			q->v = 1;
			p->next[id] = q;
			p=p->next[id];
		}
		else 
		{
			p = p->next[id];
			p->v++;
		}
	}
}

int findTrie(string str)
{
	Trie *p = root;
	for(int i=0;i<str.length();++i)
	{
		int id = str[i]-'a';
		p = p->next[id];
		if(p == NULL)
			return 0;
	}
	return p->v;
}

AC自动机

用途:是一种多模匹配算法,给你很多个单词,然后给你一段字符串,问你有多少个单词在这个字符串中出现过。
代码:

const int M = 26;
class node{
public:
    node *fail;
    node *next[M];
    int count;
    node()
    {
        count=0;
        for(int i=0;i<M;++i)
			next[i] = NULL;
    }
};
string str;

void insert(node *root,string s)
{
    node *p = root;
    for(int i=0;i<s.size();i++)
    {
        int id = s[i]-'a';
        if(p->next[id]==NULL)
			p->next[id]=new node();
        p=p->next[id];
    }
    p->count ++;  
}
 
void bulidFail(node *root)  
{
	queue< node* > q; 
    root->fail=NULL;  
    q.push(root);  
    while(!q.empty())  
    { 
        node *temp = q.front(),*p;
        q.pop();
        for(int i=0;i<26;i++)  
            if(temp->next[i]!=NULL)  
            {  
                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.push(temp->next[i]);  
			}  
    }  
}

void find(node *root)  
{  
    int cnt=0;  
    node *temp = root;  
    for(int i=0;i<str.size();i++)  
    {  
        int id = str[i]-'a';  
        while(temp->next[id]==NULL && temp != root)
			temp = temp->fail ;  
        temp = temp->next[id];  
        if(temp == NULL)
			temp = root;  
        node *p = temp;  
        while(p != root && p->count !=-1)  
        {  
            cnt += p->count;  
            p->count = -1;  
            p=p->fail;  
        }  
    }  
    cout<<cnt<<endl;  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值