使用Rabin-Karp算法找到最长的回文子串

时间:2018-06-14 08:22:52

标签: string algorithm data-structures rabin-karp

来自https://algs4.cs.princeton.edu/53substring/

  

15。最长的回文子串。给定一个字符串s,找到最长的   子串是回文(或Watson-crick回文)。

     

解决方案:可以使用后缀树或线性时间解决   Manacher的算法。这是一个通常运行的更简单的解决方案   线性时间。首先,我们描述如何找到所有回文   线性时间长度恰好为L的子串:使用Karp-Rabin   迭代地形成长度为L的每个子串的散列(及其   反过来),并进行比较。既然你不知道L,反复加倍你的   猜测L,直到你知道最佳长度在L和2L之间。然后   使用二进制搜索来找到确切的长度。

我不明白的是最后一部分。

  

由于你不知道L,反复加倍你对L的猜测   知道最佳长度在L和2L之间。

我怎么知道什么是“最佳”长度?

P.S。:之前曾经问过最长的回文子串问题,但唯一有用的问题是this,而且它也没有使用Rabin-Karp。

修改: 这是我根据收到的答案提出的代码。

public static String longestPalindrome(String key) {
    int r = 256;
    long q = longRandomPrime();
    boolean lastFound;
    boolean found;
    int l = 2;

    do {
        lastFound = indexOfPalindromeOfGivenLength(key, l, r, q) >= 0;
        l *= 2;
        found = indexOfPalindromeOfGivenLength(key, l, r, q) >= 0;
    } while (l < key.length() && !(lastFound && !found));

    int left = l / 2;
    int right = l;

    while (left <= right) {
        System.out.printf("Searching for palindromes with length between: %d and %d%n", left, right);

        int i = indexOfPalindromeOfGivenLength(key, left, r, q);
        lastFound = i >= 0;
        int j = indexOfPalindromeOfGivenLength(key, right, r, q);
        found = j >= 0;

        if (lastFound && found) return key.substring(j, j + right);

        int x = left + (right - left) / 2;
        if (!found) right = x;
        else left = x;
    }

    return null;
}

private static int indexOfPalindromeOfGivenLength(String key, int l, int r, long q) {
    System.out.printf("Searching for palindromes with length: %d%n", l);

    for (int i = 0; i + l <= key.length(); i++) {
        String s1 = key.substring(i, i + l);
        long h1 = hash(s1, r, q);
        long h2 = hash(new StringBuilder(s1).reverse().toString(), r, q);

        if (h1 == h2) {
            System.out.printf("Found palindrome: %s of length: %d%n", s1, s1.length());
            return i;
        }
    }
    System.out.printf("No palindromes of length %d exist%n", l);
    return -1;
}

1 个答案:

答案 0 :(得分:2)

一旦到达L,其中有一个长度为L的回文子字符串且没有长度为2L的回文子字符串,您知道最佳长度介于{{1}之间}和L

两个发现你使用二进制搜索。首先尝试2L如果有这个长度的回文子串与L + ceil(L/2)L + ceil(L/2)做同样的事情,同样如果没有这个长度的回文子串,那么在{{1}中搜索}。