zoukankan      html  css  js  c++  java
  • 字符串--后缀数组的运用

    后缀数组的运用主要体现在三个数组的使用之中

    1.sa[i]=n;
    表示的是排名是第i名的是第n个后缀
    2.rank[n]=i;
    表示的是第n个后缀在排序中是排在第几位的,它和sa数组是相反的。
    3.height[ ]
    表示的是相邻的两个后缀之间的最长的公共前缀。
    这三种数组的运用是有很多种,先总结两种。
    一,求出现至少k次的最长不重复子串
    这就是height[ ]最典型的运用。一般的思路是二分总的字符串的长度,来寻找符合条件的height[ ]中的段落,一旦出现符合条件的段落就记录下来,同时输出就可以。
    例题  UVA - 11107
    题意:给出n个字符串,要求你找出至少在(n)/2个字符串中出现过的最长字串。
    思路;这是一道典型的使用height[ ]数组的题目,这里只需要将给出的字符串都合并起来,同时在每一个合并的地方加上一个从来都没有出现过的字符,避免在两个字符串相交的地方出现符合条件的字串。同时在最后合并的最后加上一个没有出现过的最小的字符。这是为了,在建立三个数组的时候更好操作。所以这题我们只要对一个长度进行二分,然后在height[ ]数组中分段就好了。那么我们选择什么长度呢,这里只要选择所有给出的串中最长的一个,显然这是很符合条件的。那么下面就是代码
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<string>
    #include<vector>
    #include<stack>
    #include<bitset>
    #include<cstdlib>
    #include<cmath>
    #include<set>
    #include<list>
    #include<deque>
    #include<map>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const double PI = acos(-1.0);
    const double eps = 1e-6;
    const int  mod =1000000;
    const int maxn =140110;
    char  s[1100];
    int str[maxn];
    int Rank[maxn],height[maxn];
    int sa[maxn],t[maxn],t2[maxn],c[maxn];
    int belong[maxn],visit[200];
    void build_sa(int * s,int n,int m)
    {
    	int i,*x = t,*y = t2;
    	for(i = 0;i < m;i++)c[i] = 0;
    	for(i = 0;i < n;i++)c[ x[i] = s[i] ]++;
    	for(i = 1;i < m;i++)c[i] += c[i-1];
    	for(i = n-1;i >= 0;i--)	sa[--c[x[i]]] = i;
    	for(int k = 1;k <= n;k <<= 1)
    	{
    		int p = 0;
    		for(i = n - k;i < n;i++)	y[p++] = i;
    		for(i = 0;i < n;i++)	if(sa[i] >= k)	y[p++] = sa[i] - k;
    		for(i = 0;i < m;i++)	c[i] = 0;
    		for(i = 0;i < n;i++)	c[ x[y[i]] ]++;
    		for(i = 0;i < m;i++)	c[i] += c[i-1];
    		for(i = n-1;i >= 0;i--)	sa[--c[x[y[i]]]] = y[i];
    		swap(x,y);
    		p = 1;	x[sa[0]] = 0;
    		for(i = 1;i < n;i++)
    			x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1] + k] == y[sa[i] + k] ? p-1:p++;
    		if(p >= n)	break;
    		m = p;
    	}
    }
    
    void calheight(int * s,int n)
    {
    	int i,j,k = 0;
    	for(i = 0;i < n;i++)Rank[sa[i]] = i;
    	for(i = 0;i < n;i++)
    	{
    		if(k) k--;
    		int j = sa[Rank[i]-1];
    		while(s[i+k] == s[j+k])	k++;
    		height[Rank[i]] = k;
    	}
    }
    int Judge(int n,int len,int num)
    {
        int i,j,k;
        int cnt=0;
        memset(visit,0,sizeof(visit));
        visit[0]=1;
        if(!visit[belong[sa[0]]])
        {
            cnt++;
            visit[belong[sa[0]]]=1;
        }
        for(i=1;i<n;i++)
        {
            if(height[i]<len)
            {
                cnt=0;
                memset(visit,0,sizeof(visit));
                visit[0]=1;
                if(!visit[belong[sa[i]]])
                {
                    cnt++;
                    visit[belong[sa[i]]]=1;
                }
            }
            else
            {
                if(!visit[belong[sa[i]]])
                {
                    cnt++;
                    visit[belong[sa[i]]]=1;
                }
            }
            if(cnt>=num) return 1;
        }
        return 0;
    }
    void out(int n,int len,int num)
    {
        int i,j,cnt=0;
        memset(visit,0,sizeof(visit));
        visit[0]=1;
        if(!visit[belong[sa[0]]])
        {
            cnt++;
        }
        visit[belong[sa[0]]]=1;
        for(i=1;i<n;i++)
        {
            if(height[i]<len)
            {
                if(cnt>=num)
                {
                    for(j=sa[i-1];j<sa[i-1]+len;j++)
                        printf("%c",str[j]-20);
                    printf("
    ");
                }
                cnt=0;
                memset(visit,0,sizeof(visit));
                visit[0]=1;
                if(!visit[belong[sa[i]]])
                {
                    cnt++;
                    visit[belong[sa[i]]]=1;
                }
            }
            else
            {
                if(!visit[belong[sa[i]]])
                {
                    cnt++;
                    visit[belong[sa[i]]]=1;
                }
            }
        }
        if(cnt>=num)
        {
            for(j=sa[n-1];j<sa[n-1]+len;j++)
                printf("%c",str[j]-20);
            printf("
    ");
        }
    }
    int main()
    {
        int n;
        int flag=1;
        while(scanf("%d",&n)==1&&n)
        {
            if(!flag) printf("
    ");
            else flag=0;
            int i,j,k;
            int pos=0,cnt=1,left=0,right=0;
            memset(belong,0,sizeof(belong));
    
            for(i=1;i<=n;i++)
            {
                scanf("%s",s);
                int num=strlen(s);
                right=max(right,num);
                for(j=0;j<num;j++)
                {
                    str[pos+j]=int(s[j])+20;
                    belong[pos+j]=i;
                }
                str[pos+num]=cnt++;
                pos=pos+num+1;
            }
            str[pos]=0;
            build_sa(str,pos+1,150);
            calheight(str,pos+1);
            int max_x=0;
            while(left<=right)
            {
                int mid=(left+right)>>1;
                if(Judge(pos+1,mid,n/2+1))
                {
                    max_x=mid;
                    left=mid+1;
                }
                else
                {
                    right=mid-1;
                }
            }
            //cout<<max_x<<"....."<<endl;
            if(max_x==0)
            {
                printf("?
    ");
            }
            else
            {
                out(pos+1,max_x,n/2+1);
            }
        }
        return 0;
    }
    
    2.求出现k次或者是至少k次的最长可重叠子串
    这个问题和上面的问题就很类似,实际上差别就不会很大,上面的要求是不能重叠,而这里则是可以重叠的,那么反而这个类型是更加简单的。同样的方法解答,但是不需要记录每一个对height[ ]遍历的时候辨别当前的子串是不是属于同一个已经辨别过的子串。
    题意:给你一个n和一个字符串,要求你求出在这个字符串中出现了n次的最长字串的长度以及最后一个出现的位置。
    思路;这一题时间上十分的简单,只要二分height[ ]数组,同时注意输出就好了。
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<string>
    #include<vector>
    #include<stack>
    #include<bitset>
    #include<cstdlib>
    #include<cmath>
    #include<set>
    #include<list>
    #include<deque>
    #include<map>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const double PI = acos(-1.0);
    const double eps = 1e-6;
    const int  mod =1000000;
    const int maxn =140110;
    char  s[50000];
    int str[maxn];
    int Rank[maxn],height[maxn];
    int sa[maxn],t[maxn],t2[maxn],c[maxn];
    int max_i;
    int max_x=0;
    void build_sa(int * s,int n,int m)
    {
    	int i,*x = t,*y = t2;
    	for(i = 0;i < m;i++)c[i] = 0;
    	for(i = 0;i < n;i++)c[ x[i] = s[i] ]++;
    	for(i = 1;i < m;i++)c[i] += c[i-1];
    	for(i = n-1;i >= 0;i--)	sa[--c[x[i]]] = i;
    	for(int k = 1;k <= n;k <<= 1)
    	{
    		int p = 0;
    		for(i = n - k;i < n;i++)	y[p++] = i;
    		for(i = 0;i < n;i++)	if(sa[i] >= k)	y[p++] = sa[i] - k;
    		for(i = 0;i < m;i++)	c[i] = 0;
    		for(i = 0;i < n;i++)	c[ x[y[i]] ]++;
    		for(i = 0;i < m;i++)	c[i] += c[i-1];
    		for(i = n-1;i >= 0;i--)	sa[--c[x[y[i]]]] = y[i];
    		swap(x,y);
    		p = 1;	x[sa[0]] = 0;
    		for(i = 1;i < n;i++)
    			x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1] + k] == y[sa[i] + k] ? p-1:p++;
    		if(p >= n)	break;
    		m = p;
    	}
    }
    
    void calheight(int * s,int n)
    {
    	int i,j,k = 0;
    	for(i = 0;i < n;i++)Rank[sa[i]] = i;
    	for(i = 0;i < n;i++)
    	{
    		if(k) k--;
    		int j = sa[Rank[i]-1];
    		while(s[i+k] == s[j+k])	k++;
    		height[Rank[i]] = k;
    	}
    }
    int Judge(int n,int len,int num)
    {
        int cnt=1;
        int i,j;
        for(i=1;i<n;i++)
        {
            if(height[i]<len)
            {
                cnt=1;
            }
            else
            {
                cnt++;
            }
            if(cnt>=num)
            {
                return 1;
            }
        }
        return 0;
    }
    void out(int n,int len,int num)
    {
        int cnt=1;
        int i,j;
        for(i=1;i<n;i++)
        {
            if(height[i]<len)
            {
                cnt=1;
            }
            else
            {
                cnt++;
            }
            if(cnt>=num)
            {
                int num2=cnt;
                for(j=i-cnt+1;j<=i;j++)
                {
                    if(sa[j]>=max_i)
                    {
                        max_i=sa[j];
                    }
                }
            }
        }
        printf("%d %d
    ",max_x,max_i);
    }
    int main()
    {
        int n;
        while(scanf("%d",&n)==1&&n)
        {
            int i,j,k;
            scanf("%s",s);
            int num=strlen(s);
            for(i=0;i<num;i++)
            {
                str[i]=int(s[i]);
            }
            str[num]=0;
            build_sa(str,num+1,200);
            calheight(str,num+1);
            int l=0,r=num;
            max_x=0;
            max_i=0;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                if(Judge(num+1,mid,n))
                {
                    max_x=mid;
                    l=mid+1;
                }
                else
                {
                    r=mid-1;
                }
            }
            if(n==1)
            {
                printf("%d 0
    ",num);
            }
            else{
            if(max_x==0)
            {
                printf("none
    ");
            }
            else
            {
                out(num+1,max_x,n);
                //cout<<max_x<<endl;
            }
            }
        }
        return 0;
    }
    

      待续....

      

  • 相关阅读:
    3spring:生命周期,属性赋值,自动装配
    2spring注解:@Lazy,@Conditional,@import,FactoryBean接口
    1spring注解:@Configuration,@Bean,@ComponentScan(),@Scope
    10.spring:常用的数据库代码.....(不长使用了解即可)
    9.spring:事务管理(下):声明式事务管理
    原生JavaScript实现hasClass、addClass、removeClass、toggleClass
    表格去重复边框
    缓存工厂之Redis缓存
    【实践】Memcached实例解析
    c# is和as的区别
  • 原文地址:https://www.cnblogs.com/yewa/p/7801293.html
Copyright © 2011-2022 走看看