zoukankan      html  css  js  c++  java
  • 后缀数组-另辟蹊径

    参考资料

    后缀数组新手向入门 by xMinh

    后缀数组——强大的字符串处理工具 by laeva

    后缀数组 by hyfhaha

    2012年noi冬令营陈立杰讲稿

    罗穗骞《后缀数组——处理字符串问题的有力工具》

    1. 朴素算法

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    typedef unsigned long long ULL;
    using namespace std;
    const int N=1e6+5;
    char a[N];
    int n;
    int sa[N];
    inline bool rule(int p,int q)
    {
    	for(int i=0;p+i<=n&&q+i<=n;i++) {
    		if(a[p+i]!=a[q+i])
    			return a[p+i]<a[q+i];
    	}
    	return p>q;
    }
    int main()
    {
    //	freopen("1.in","r",stdin);
    	int i;
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	for(i=1;i<=n;i++) sa[i]=i;
    	sort(sa+1,sa+n+1,rule);
    	for(i=1;i<=n;i++) 
    		printf("%d ",sa[i]);
    	return 0;
    }
    

    2 . Hash+binary

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    typedef long long LL;
    typedef unsigned long long ULL;
    using namespace std;
    const int N=1e6+5;
    const ULL P=131;
    char a[N];
    int n;
    int sa[N];
    ULL h[N],POW[N];
    inline ULL get(int l,int r)
    {
    	return h[r]-h[l-1]*POW[r-l+1];
    }
    inline bool rule(int p,int q)
    {
    	int L=-1,R=min(n-p,n-q)+1,mid;
    	while(L+1<R) {
    		mid=(L+R)>>1;
    		if(get(p,p+mid)==get(q,q+mid)) L=mid;
    		else R=mid;
    	}
    	p=p+L+1; q=q+L+1;
    	if(p==n+1||q==n+1) return (p==n+1);
    	else return a[p]<a[q];
    }
    int main()
    {
    //	freopen("1.in","r",stdin);
    	int i;
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	POW[0]=1;
    	for(i=1;i<=n;i++) {
    		sa[i]=i;
    		h[i]=h[i-1]*P+a[i];
    		POW[i]=POW[i-1]*P;
    	}
    	sort(sa+1,sa+n+1,rule);
    	for(i=1;i<=n;i++) 
    		printf("%d ",sa[i]);
    	return 0;
    }
    

    3. Hash+倍增

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    typedef long long LL;
    typedef unsigned long long ULL;
    using namespace std;
    const int N=1e6+5;
    const ULL P=131;
    char a[N];
    int n;
    int sa[N];
    ULL h[N],POW[N];
    inline ULL get(int l,int r)
    {
    	return h[r]-h[l-1]*POW[r-l+1];
    }
    inline bool rule(int p,int q)
    {
    	int base=1;
    	while(base>0) {
    		if(p+base-1>n||q+base-1>n) base>>=1;
    		else if(get(p,p+base-1)==get(q,q+base-1)) {
    			p+=base; q+=base;
    			base<<=1;
    		}
    		else base>>=1;
    	}
    	if(p==n+1||q==n+1) return (p==n+1);
    	else return a[p]<a[q];
    }
    void print(int x)
    {
    	if(x>=10) print(x/10);
    	putchar(x%10+'0');
    }
    int main()
    {
    //	freopen("1.in","r",stdin);
    	int i;
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	POW[0]=1;
    	for(i=1;i<=n;i++) {
    		sa[i]=i;
    		h[i]=h[i-1]*P+a[i];
    		POW[i]=POW[i-1]*P;
    	}
    	sort(sa+1,sa+n+1,rule);
    	for(i=1;i<=n;i++) 
    		print(sa[i]),putchar(' ');
    	return 0;
    }
    

    倍增在随机数据下运行效率很高,但常数较大。

    二分在构造数据下会快不少。

  • 相关阅读:
    进程
    Visual Studio Code 使用教程
    C# 多线程中的lock与token模式
    JavaScript中的多态
    简说GC垃圾回收
    C# 简单的SQLHelper
    JavaScript中addEventListener/attachEvent 与内联事件
    JavaScript中事件冒泡与事件捕获
    ASP.Net ScriptManager 与 UpdatePanel
    Nhibernate 使用sql语句查询
  • 原文地址:https://www.cnblogs.com/cjl-world/p/13545345.html
Copyright © 2011-2022 走看看