子字符串查找:Rabin-Karp算法(指纹字符串查找算法)

参考网站:
https://blog.csdn.net/fjssharpsword/article/details/53462292
https://cloud.tencent.com/developer/article/1139653
参考书籍:Algorithm (算法) Robert Sedgewick / Kevin Wayne著 谢路云译

1. 题目描述

查找目标字符串K中是否有与字符串L匹配的子串

2. 关键词

哈希

3. 思路
  1. 当子串L的长度为m,目标字符串K的长度为n
  2. 计算子串L的hash值
  3. 使用华东窗口,计算目标字符串K中每个长度为m的子串的hash值(共需要计算n-m+1次)
  4. 依次比较hash值并且对997取余(在不溢出的情况下选择一个尽可能大的值)。

在计算机中,当要表示的数据超出计算机所使用的数据的表示范围时,则产生数据的溢出

  1. 如果hash值不同,字符串必然不匹配,如果hash值相同,还需要使用朴素算法再次判断。
4. 时间及空间复杂度

时间复杂度:O(M+N)

空间复杂度:O(1)

5. 代码(Java)
public class RabinKarp {
    private String pat;    
    private long patHash;   
    private int m;       
    private long q;       
    private int R;         
    private long RM;      
    //字符串hash值计算方法
    private long hash(String key, int m) {    
    long h = 0; 
    for (int j = 0; j < m; j++) 
        h = (R * h + key.charAt(j)) % q;
    return h;
}
    public RabinKarp(String pat) {
        this.pat = pat;
        R = 256;
        m = pat.length();
        q = longRandomPrime();
        RM = 1;
        for (int i = 1; i <= m-1; i++)
        RM = (R * RM) % q;
        patHash = hash(pat, m);
    } 
    private long hash(String key, int m) { 
        long h = 0; 
        for (int j = 0; j < m; j++) 
            h = (R * h + key.charAt(j)) % q;
        return h;
    }
    private boolean check(String txt, int i) {
        for (int j = 0; j < m; j++) 
            if (pat.charAt(j) != txt.charAt(i + j)) 
                return false; 
        return true;
    }
    public int search(String txt) {
        int n = txt.length(); 
        if (n < m) return n;
        long txtHash = hash(txt, m); 
        if ((patHash == txtHash) && check(txt, 0))
            return 0;
        for (int i = m; i < n; i++) {
            txtHash = (txtHash + q - RM*txt.charAt(i-m) % q) % q; 
            txtHash = (txtHash*R + txt.charAt(i)) % q; 
            int offset = i - m + 1;
            if ((patHash == txtHash) && check(txt, offset))
                return offset;
        }
        return n;
    }   
    private static long longRandomPrime() {
        BigInteger prime = BigInteger.probablePrime(31, new Random());
        return prime.longValue();
    }
}
发布了82 篇原创文章 · 获赞 0 · 访问量 871

猜你喜欢

转载自blog.csdn.net/weixin_43518038/article/details/105156058