通用字符串算法

一、Rabin-Karp算法

将字符串映射为一个Hash值,通过比较Hash值判断字符串是否相等。

选用的Hash函数:

把字符串看作一个b进制数(一个多项式),计算它(在十进制下)对p取模的值

举例:

取b=131,p=2^64
字符串foobar的Hash值为(a=1, b=2, f=6, o=15, r=18)
(6*1315+15*1314+15*1313+2*1312+1*131+18) mod 264
:选取的b和p的值决定了Hash函数的质量,
根据经验,b=131,13331等,p为大质数,冲突概率小
Hash值相等时可以再对比一下两个字符串,避免Hash碰撞问题

计算一个子串的Hash值

s=“foobar”
计算6个前缀子串的Hash值,O(n):
H[i] = Hash (s [0…i-1]) = (H[i-1] * b + s[i-1]) mod p
计算子串oba的Hash值
相当于b进制下两个数做减法(H[5] - H[2] * b3
Hash(s[l…r]) = (H[r+1]-H[l]*br-l+1) mod p

leetcode28

class Solution {
private:
    int p = 1e9+7;
    int b = 131;
    vector<long> p131;
private:
    //计算子串hash值
    long calcHash(vector<long>& sHash, int l, int r){
         return return ((sHash[r]-sHash[l-1]*p131[r-l+1])%p+p)%p;
         //注:有负数取模还在负数里面,需要加p再模p
    }
public:
    int strStr(string haystack, string needle) {
        if(needle.size()==0) return 0;
        int n = haystack.size();
        int m = needle.size();
        string s=" "+haystack;
        string t=" "+needle;
        //求s的所有前缀hash值
        vector<long> sHash(n+1, 0);
        for(int i=1; i<=n; ++i){
            sHash[i] = (sHash[i-1]*b+s[i]-'a'+1)%p;
        }
        //求t的hash值
        long tHash = 0;
        for(int i=1; i<=m; ++i){
            tHash = (tHash*b+t[i]-'a'+1)%p;
        }
        //求进制
        p131 = vector<long>(n+1);
        p131[0] = 1;
        for(int i=1; i<=n; ++i){
            p131[i]=p131[i-1]*131%p;
        }
        //匹配过程
        for(int i=m; i<=n; ++i){
            if(calcHash(sHash, i-m+1, i)==tHash && s.substr(i-m+1, m)==needle){
                return i-m;
            }
        }
        return -1;
    }
};

二、字符串匹配——KMP

class Solution {
private:
    void getNext(vector<int>& next, string needle){
        int j=0;//指向前缀末尾,同时代表最长相等前后前后缀的个数
        next[0]=0;
        //i指向后缀末尾
        for(int i=1; i<needle.size(); ++i){
			while(j>0 && needle[i]!=needle[j]){
				j = next[j-1];//找j前一位的next
			}
			if(needle[i]==needle[j]) j++;
			next[i]=j;
		}
    }
public:
    int strStr(string haystack, string needle) {
        vector<int> next(needle.size());
        getNext(next, needle);
        int j=0;//指向needle中正在匹配的位置
        for(int i=0; i<haystack.size(); ++i){
			while(j>0 && haystack[i]!=needle[j]){
				j = next[j-1];
			}
			if(haystack[i]==needle[j]) j++;
			if(j==needle.size()) return i-j+1;
		}
		return -1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值