• 字符串匹配算法之Rabin-Karp算法


    关键思想在于把输入的字符既看作图形符号,又看做数字,预处理算出模式P的d进制的值p,时间复杂度为Θ(m),让后针对n - m + 1个有效偏移s计算出相应的ts,这里是由于利用ts来计算ts+1,时间复杂度是Θ(1),因此总的时间复杂度为Θ(n - m + 1),为了避免p和ts的值太大,不能在常数时间里计算,引入一个合适的素数q,p和ts对q取模,这样数就不至于太大,关键的步骤是把p和ts逐个进行比较找出所有的伪命中点s,再用平凡的比较方法比较P[1..m]和T[s + 1.. s + m]是否相等得到s是否为一个命中点。

    该算法的运行时间为O(m) + O(n - m + 1),最坏情况下为O((n - m + 1)m),期望的复杂度为O(n)。代码实现为:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int pow_of_d(int d, int m)
    {
    	int res = 1;
    	while(m > 0)
    	{
    		if(m & 1) res = res * d;
    		d = d * d;
    		m >>= 1;
    	}
    	return res;
    }
    
    void RABIN_KARP_MATCHER(string T, string P, int d, int q)
    {
    	int n = T.length();
    	int m = P.length();
    	int h = pow_of_d(d, m - 1) % q;
    
    	int p = 0;
    	int t = 0;
    	for(int i = 0; i < m; i++)
    	{
    		p = (d * p + (P[i] - 48)) % q;
    		t = (d * t + (T[i] - 48)) % q;
    	}
    
    	for(int s = 0; s <= n - m; s++)
    	{
    		if(t == p)
    		{
    			bool flag = true;
    			for(int i = 0; i < m; i++)
    			{
    				if(P[i] != T[s + i])
    				{
    					flag = false;
    					break;
    				}
    			}
    			if(flag)
    				cout<<s<<endl;
    		}
    		if(s < n - m)
    		{
    			t = ((d * (t - (T[s] - 48) * h) + (T[s + m] - 48)) % q + q) % q;
    		}
    	}
    }
    
    
    int main()
    {
    	string T = "2359023141526739921";
    	string P = "31415";
    	int d = 10;
    	int q = 13;
    	RABIN_KARP_MATCHER(T, P, d, q);
    	return 0;
    }
    
  • 相关阅读:
    Kafka调试入门(一)
    java笔记十五——多线程
    java笔记十四——初始集合源码
    java笔记十二——集合总结
    java笔记十一——异常
    java笔记十——大数类和日期类
    java笔记九——Object类与String类
    java笔记八——面向对象(三)
    java笔记七——面向对象(二)
    java笔记六——面向对象(一)
  • 原文地址:https://www.cnblogs.com/wwblog/p/3953952.html
Copyright © 2020-2023  润新知