【问题标题】:Leetcode 1044. Longest Duplicate Substring (small question in terms of modulus)Leetcode 1044. 最长重复子串(模数方面的小问题)
【发布时间】:2020-12-25 05:00:26
【问题描述】:

我正在解决Leetcode 1044,答案是使用二进制搜索和滚动哈希。基本上使用二进制搜索来选择一个长度,然后搜索该长度的重复字符串。这里滚动散列发挥作用以节省空间(我们存储子字符串的散列而不是使用集合来存储所有子字符串)。这就是解决方案的背景。

我的问题是关于用于防止溢出的模数。我选择了 Long.MAX_VALUE,我认为它足够大,可以处理它,但是当我使用 Long.MAX_VALUE 时答案不正确。但是,当我使用 Long.MAX_VALUE / 26 或 Math.pow(2, 32) 时,它们都可以工作。抱歉,我对模数不太了解,我想我肯定在这里错过了一些东西。任何人都可以对此有所了解吗?谢谢!以下是我的解决方案:

public static long modulus = Long.MAX_VALUE / 26;
public String longestDupSubstring(String S) {
    int n = S.length();
    int l = 1;
    int r = n - 1;
    int index = -1;
    while (l <= r) {
        int m = l + (r - l) / 2;
        int temp = findDuplicate(S, m);
        if (temp != -1) {
            index = temp;
            l = m + 1;
        }
        else {
            r = m - 1;
        }
    }
    return index == -1 ? "" : S.substring(index, index + r);
}
private int findDuplicate(String s, int len) {
    Set<Long> set = new HashSet<>();
    long hash = 0;
    long p = 1;
    for (int i = 0; i < len; i++) {
        hash = (hash * 26 + s.charAt(i) - 'a') % modulus;
        p = (p * 26) % modulus;
    }
    set.add(hash);
    
    for (int i = len; i < s.length(); i++) {
        hash = (hash * 26 + (s.charAt(i) - 'a')
                - (s.charAt(i - len) - 'a') * p) % modulus;
        if (hash < 0) {
            hash += modulus;
        }
        if (set.contains(hash)) {
            return i - len + 1;
        }
        set.add(hash);
    }
    return -1;
}

【问题讨论】:

  • longValue % Long.MAX_VALUE 的意义何在?除非longValue完全等于Long.MAX_VALUE,否则表达式将执行... nothing

标签: java math hash modulus rabin-karp


【解决方案1】:

26 不是模数的一部分,是散列的一部分。如果我们在算法中将它们分开,那么我们可能会看到它是如何工作的。对于模数,通常一个大数字就足够了,不必是long

public final class Solution {
    int a = 26;
    int mod = 1 << 29;

    public final String longestDupSubstring(
        final String s
    ) {
        int lo = 1;
        int hi = s.length() - 1;

        while (lo <= hi) {
            int mid = lo + ((hi - lo) >> 1);
            int startIndex = search(s, mid);

            if (startIndex == - 1) {
                hi = mid - 1;
            }

            else {
                lo = -~mid;
            }
        }

        int startIndex = search(s, hi);
        return startIndex == -1 ? "" : s.substring(startIndex, startIndex + hi);
    }

    public final int search(
        final String s,
        final int len
    ) {
        long h = 0;
        long aL = 1;

        for (int i = 0; i < len; i++) {
            h = (h * a % mod + s.charAt(i)) % mod;
            aL = aL * a % mod;
        }

        HashMap<Long, List<Integer>> visited = new HashMap<>();
        visited.put(h, new ArrayList<Integer>());
        visited.get(h).add(0);

        for (int i = 1; i < -~s.length() - len; i++) {
            h = ((h * a % mod - s.charAt(i - 1) * aL % mod + mod) % mod + s.charAt(i + len - 1)) % mod;

            if (visited.containsKey(h)) {
                for (int start : visited.get(h)) {
                    if (s.substring(start, start + len).equals(s.substring(i, i + len))) {
                        return i;
                    }
                }

            } else {
                visited.put(h, new ArrayList<Integer>());
            }

            visited.get(h).add(i);
        }

        return -1;
    }
}

【讨论】:

    猜你喜欢
    • 2017-06-20
    • 2012-06-07
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 2018-10-18
    • 2021-12-26
    • 1970-01-01
    • 2020-11-25
    相关资源
    最近更新 更多