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;
    }
    

      待续....

      

  • 相关阅读:
    leetcode108 Convert Sorted Array to Binary Search Tree
    leetcode98 Validate Binary Search Tree
    leetcode103 Binary Tree Zigzag Level Order Traversal
    leetcode116 Populating Next Right Pointers in Each Node
    Python全栈之路Day15
    Python全栈之路Day11
    集群监控
    Python全栈之路Day10
    自动部署反向代理、web、nfs
    5.Scss的插值
  • 原文地址:https://www.cnblogs.com/yewa/p/7801293.html
Copyright © 2011-2022 走看看