• 【挑战程序设计竞赛】后缀数组 实现字符串匹配


    字符串后缀Suffix 指的是从字符串的某个位置开始到其末尾的字符串字串

    后缀数组 Suffix Array 指的是将某个字符串的所有后缀按字典序排序之后得到的数组,不过数组中不直接保存所有

    的后缀子串,只要记录相应的位置就好了。

    下面的代码使用倍增法来构造后缀数组,该算法的复杂度是 O(n log n)常数因子比较大。

    基于后缀数组的字符串匹配,我们可以通过二分搜索来完成,算法复杂度是 O(|T|log|S|) 其中 S 是主串,T是模式串

    具体的后缀数组的原理可以详细去看看国家队集训的论文,罗穗骞《后缀数组——处理字符串的有力工具》:

    #include <iostream>
    #include <cstring>
    #include <cstddef>
    #include <cstdio>
    #include <string>
    #include <algorithm> 
    
    using namespace std;
    const int MAXN = 10001;
    int n,k;
    int rank[MAXN+1],tmp[MAXN+1];
    
    bool comp_sa(int i, int j)
    {
    	if(rank[i] != rank[j]) 
    		return rank[i] < rank[j];
    	int ri = i+k <= n? rank[i+k] : -1;
    	int rj = j+k <= n? rank[j+k] : -1;
    	return ri < rj; 
    }
    
    void calc_sa(string &S, int *sa) //计算字符串S的后缀数组 
    {
    	n = S.size();
    	
    	//初始长度为1 
    	for(int i = 0; i <= n; i++)
    	{
    		sa[i] = i;
    		rank[i] = i < n ? S[i] : -1;
    	}
    	
    	for( k =1; k <= n; k *= 2)
    	{
    		sort(sa,sa+n+1,comp_sa);
    		
    		//先在tmp中临时存储新计算的rank,再转存回rank中 
    		tmp[sa[0]] = 0;
    		for(int i = 1; i <= n; i++)
    		{
    			tmp[sa[i]] = tmp[sa[i-1]] + (comp_sa(sa[i-1],sa[i]) ? 1: 0);
    		}
    		for(int i = 0; i <= n; i++)
    		{
    			rank[i] = tmp[i];
    		}
    	}
    }
    
    void SuffixArrayMatch(string &S, int *sa, string T)
    {
    	calc_sa(S,sa);
    	int lhs = 0, rhs = S.size();
    	
    	//使用二分查找 
    	while(rhs - lhs > 1)
    	{
    		int mid = (lhs + rhs)>>1;
    		int res = S.compare(sa[mid],T.size(),T); 
    		if(res < 0)
    			lhs = mid;
    		else if(res == 0) 
    		{
    			cout<<"match at: "<<sa[mid]<<endl;
    			lhs = mid;
    		}
    		else rhs = mid;
    	}
    }
    int main()
    {
    	string S = "abracadabra";
    	string T = "ab";
    	int *sa = new int[S.size()+1];
     	SuffixArrayMatch(S,sa,T);
     	delete [] sa;
     	sa = NULL;
    }


  • 相关阅读:
    内存问题定位与解决
    CPU问题定位与解决
    数据库优化案例——————某市中心医院HIS系统
    系统隐形杀手——阻塞与等待
    SQL Server常见问题介绍及快速解决建议
    CVTE实习感想--2014.10秋招
    Spring AOP的理解
    一些Java面试问题
    举几个大数据的例子
    Java中乐观锁与悲观锁的实现
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3356097.html
Copyright © 2020-2023  润新知