zoukankan      html  css  js  c++  java
  • 字符串模板

    模板

    next数组

    //下标从0开始
    int Next[maxn];//Next[i]是p[0~i-1]的前缀等于后缀的最大长度(下标+1) 
    void next_pre(int m){
    	int i,j;
    	j=Next[0]=-1;//检测到j==-1时就停止迭代
    	i=0;
    	while(i<m){
    		while(-1!=j &&p[i]!=p[j])j=Next[j];
    		Next[++i]=++j;
    	}
    }
    

    kmp

    可以统计模式串的出现次数

    //洛谷P3375,输出s2在s1中出现的每个位置,答案的下标从1开始
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e6 + 5;
    int nxt[N];
    char s1[N], s2[N];
    void get_next(char* s,int l, int* nxt) { // s是模式串
        int i = 0, j = -1;
        nxt[0] = -1;
        while(i < l) {
            if(j == -1 || s[i] == s[j])
                nxt[++i] = ++j;
            else j = nxt[j];
        }
    }
    void kmp(char* p, char* s, int m, int n, int* nxt) { // p是模式串,s是文本串
        int i = 0, j = 0;
        while (i < n) {
            if(j == -1 || s[i] == p[j]) i++, j++;
            else j = nxt[j];
            if(j == m) printf("%d\n", i-m+1), j = nxt[j];
        }
    }
    int main() {
        scanf("%s%s", s1, s2);
        int len1=strlen(s1);
        int len2=strlen(s2);
        get_next(s2,len2,nxt);
        kmp(s2,s1,len2,len1,nxt);
        for (int i = 1; i <= strlen(s2); i++)
            printf("%d ", nxt[i]);
    }
    
    //下标从0开始
    int kmpNext[maxn];// kmpNext[i] 的意思:next'[i]=next[next[...[next[i]]]](直到 next'[i]<0 或者 x[next'[i]]!=x[i]) ,在kmp用这种数组更快(用Next也可以)。
    void kmp_pre(int m){
    	int i,j;
    	j=kmpNext[0]=-1;
    	i=0;
    	while(i<m){
    		while(-1!=j && p[i]!=p[j]) j=kmpNext[j];
    		if(p[++i]==p[++j])kmpNext[i]=kmpNext[j];
    		else kmpNext[i]=j;
    	}
    }
    int kmp(int n,int m){
    	int i=0,j=0;
    	while(i<n&&j<m){
    		if(j==-1 || a[i]==p[j]){//模式串首位就失配后,j==-1
    			i++;j++;
    		}
    		else j=kmpNext[j];
    	}
    	if(j==m) return i-m;
    	else return -1;
    }
    

    manachar

    char s[maxn],s1[maxn];
    int p[maxn];
    int manacher(int n){
    	int ans=0;
    	s1[0]='~';
    	s1[1]='#';
    	int cnt=1;
    	for(int i=0;i<n;i++){
    		s1[++cnt]=s[i];
    		s1[++cnt]='#';
    	}
    	int maxr=0,mid=0;
    	for(int i=1;i<=cnt;i++){
    		if(i<maxr)
    			p[i]=min(p[(mid<<1)-i],maxr-i);//对称回文的长度和
    		else p[i]=1;//p[i]为半径(包括原点)
    		while(s1[i-p[i]]==s1[i+p[i]]){
    			p[i]++;
    		}
    		if(i+p[i]-1>maxr){//看别人都是i+p[i]>maxr,不知道为啥
    			maxr=i+p[i]-1;
    			mid=i;
    		}
    		if(p[i]>ans) ans=p[i];
    	}
    	return ans-1;
    }
    int main(){
    	while(~scanf("%s",s) ){
    		int n=strlen(s);
    		printf("%d\n",manacher(n));
    	}
    }
    

    例题

    模式串计数

    https://cn.vjudge.net/contest/316613#problem/B

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int maxn=1e6+5;
    int Next[maxn];//next[i]是p[0~i-1]的前缀等于后缀的最大长度(下标+1) 
    char p[maxn];
    char a[maxn];
    void next_pre(int m){
    	int i,j;
    	j=Next[0]=-1;
    	i=0;
    	while(i<m){
    		while(-1!=j &&p[i]!=p[j])j=Next[j];
    		Next[++i]=++j;
    	}
    }
    int kmpc(int n,int m){
    	int i=0,j=0;
    	int ans=0;
    	while(i<n){
    		if(j==-1 || a[i]==p[j]){
    			if(j==m-1){
    				ans++;
    				j=Next[j+1]-1;//模式串指针跳到自身的最大前缀后缀匹配下标
    			}
    			else{
    				i++;j++;
    			}
    		}
    		else j=Next[j];
    	}
    	return ans;
    }
    int main(){
    	int t,n,m;
    	cin>>t;
    	while(t--){
    		scanf("%s",p);
    		scanf("%s",a);
    		n=strlen(a);
    		m=strlen(p);
    		next_pre(m);
    		int temp=kmpc(n,m);
    		printf("%d\n",temp);
    	}
    }
    

    Compress Words

    https://codeforces.com/contest/1200/problem/E

    题意:给定一些字符串,把前缀后缀相同的缩掉拼起来

    由于每个串最长有1e6,存储的时候不能直接开一个大二维数组,可以开两个一维数组交替存储

    从前往后遍历,把答案储存在ans[]数组中,当下一个字符串长度为l时,从答案串中拿出后l个字符拼到新串之后做一次next[]数组计算,由于start=next[l+l]可能>l,所以要递归到next[start]<=l为止( [0,start-1]和[start,l+l]相同,那么[0,start]的最大前缀后缀相同长度就是整个串的前缀后缀相同长度 )

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn=1e6+5;
    char p[maxn];
    int Next[maxn];//Next[i]是p[0~i-1]的前缀等于后缀的最大长度(下标+1) 
    void next_pre(int m){
        int i,j;
        j=Next[0]=-1;//检测到j==-1时就停止迭代
        i=0;
        while(i<m){
            while(-1!=j &&p[i]!=p[j])j=Next[j];
            Next[++i]=++j;
        }
    }
    char c1[maxn],c2[maxn],ans[maxn];
    int l1,l2,len=0;
    int main(){
    	int n,m,q;
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		if(i&1){
    			scanf("%s",c1);
    			l1=strlen(c1);
    		}
    		else{
    			scanf("%s",c2);
    			l2=strlen(c2);
    		}
    		if(i>1){
    			int temp,start,minn;
    			if(i&1){//c1
    				for(int j=0;j<l1;j++) p[j]=c1[j];
    				for(int j=max(0,len-l1),k=l1;j<len;j++,k++)
    					p[k]=ans[j];
    				temp=l1+min(l1,len);
    				minn=min(l1,len);
    			}
    			else{
    				for(int j=0;j<l2;j++) p[j]=c2[j];
    				for(int j=max(0,len-l2),k=l2;j<len;j++,k++)
    					p[k]=ans[j];
    				temp=l2+min(l2,len);
    				minn=min(l2,len);
    			}
    			next_pre(temp);
    			start=Next[temp];
    			while(start>minn) start=Next[start];//这是关键
    			if(start<=0)start=0;
    			if(i&1){
    				start=min(start,Next[temp]);
    				for(int j=start,k=len;j<l1;j++,k++)
    					ans[k]=c1[j];
    				len+=l1-start;
    			}
    			else{
    				for(int j=start,k=len;j<l2;j++,k++)
    					ans[k]=c2[j];
    				len+=l2-start;
    			}
    		}
    		else{
    			for(int j=0;j<l1;j++)
    				ans[j]=c1[j];
    			len=l1;
    		}
    	}
    	for(int j=0;j<len;j++) printf("%c",ans[j]);
    	printf("\n");
    }
    
  • 相关阅读:
    svn cleanup failed–previous operation has not finished 解决方法
    开源SNS社区系统推荐
    从网络获取图片本地保存
    MS SQL Server 数据库连接字符串
    KeepAlive
    Configure Git in debian
    sqlserver query time
    RPi Text to Speech (Speech Synthesis)
    SQL Joins with C# LINQ
    search or reseed identity columns in sqlserver 2008
  • 原文地址:https://www.cnblogs.com/ucprer/p/11315945.html
Copyright © 2011-2022 走看看