📜  在Java使用滚动哈希实现Rabin Karp算法(1)

📅  最后修改于: 2023-12-03 14:51:17.777000             🧑  作者: Mango

在Java使用滚动哈希实现Rabin Karp算法

Rabin Karp算法是一种字符串匹配算法,用于在文本串中查找某个模式串的出现位置。它通过哈希函数来快速匹配字符窗口,可以在O(n)的时间复杂度内完成匹配。

下面我们将介绍如何在Java中使用滚动哈希来实现Rabin Karp算法。

哈希函数实现

我们首先需要实现一个哈希函数,将字符串转换为一个唯一的数字。这个数字可以用于比较两个字符串是否相等。

我们可以使用类似于多项式求值的方法来实现哈希函数,即将字符串看作一个多项式,将每个字符的ASCII码视为系数,计算出多项式的值。

下面是一个使用滚动哈希实现的字符串哈希函数:

public class RabinKarpHash {
    private final int BASE = 31; // 基数
    private final long MOD = (long) 1e9 + 9; // 模数

    public long hash(String s) {
        long hashValue = 0;
        long pow = 1;
        for (int i = s.length() - 1; i >= 0; i--) {
            hashValue = (hashValue + pow * s.charAt(i)) % MOD;
            pow = (pow * BASE) % MOD;
        }
        return hashValue;
    }

    public long rollHash(long oldHash, int len, char oldChar, char newChar) {
        long newHash = (oldHash - oldChar * pow(BASE, len - 1) % MOD + MOD) % MOD;
        newHash = (newHash * BASE % MOD + newChar) % MOD;
        return newHash;
    }

    public long pow(int base, int exp) {
        if (exp == 0) {
            return 1;
        }
        long half = pow(base, exp / 2);
        if (exp % 2 == 0) {
            return half * half % MOD;
        } else {
            return half * half % MOD * base % MOD;
        }
    }
}

其中,hash()方法用于计算给定字符串的哈希值,rollHash()方法用于在滚动窗口时更新哈希值,pow()方法用于快速计算幂。

Rabin Karp算法实现

有了哈希函数,我们现在可以开始实现Rabin Karp算法了。

我们的算法首先计算模式串的哈希值,然后在文本串中以模式串长度为窗口滚动哈希,每次比较窗口哈希值与模式串哈希值是否相等。如果相等,则说明匹配成功。

下面是一个使用滚动哈希实现的Rabin Karp算法:

public class RabinKarp {
    public List<Integer> search(String pattern, String text) {
        RabinKarpHash hash = new RabinKarpHash();
        long patternHash = hash.hash(pattern);
        int n = text.length();
        int m = pattern.length();
        long hashValue = 0;
        List<Integer> matches = new ArrayList<>();
        if (m > n) {
            return matches;
        }
        for (int i = 0; i < m; i++) {
            hashValue = (hashValue * hash.BASE + text.charAt(i)) % hash.MOD;
        }
        int start = 0;
        while (start <= n - m) {
            if (hashValue == patternHash) {
                if (text.substring(start, start + m).equals(pattern)) {
                    matches.add(start);
                }
            }
            if (start < n - m) {
                hashValue = hash.rollHash(hashValue, m, text.charAt(start), text.charAt(start + m));
            }
            start++;
        }
        return matches;
    }
}

其中,search()方法用于在文本串中查找所有出现的模式串,返回一个包含出现位置的列表。

总结

使用滚动哈希实现Rabin Karp算法可以在O(n)的时间复杂度内完成字符串匹配。这个算法可以处理大规模的文本串和模式串,并且在查找过程中只需要进行哈希计算和比较操作,比较高效。