1044. Longest Duplicate Substring

这道就是Rolling Hash + Binary Search的组合。
周赛的时候笔者想到了Rolling Hash, 然后并没有想到加binary search进行优化
写了两个naive的solution 都TLE了,然而虽然这题没写出来,这次周赛还是排在300名左右不算差。
要 对Rolling hash再熟一点,我下来之后写的代码在减去最高位的时候出一个bug调了好久。
当减去最高位时, 我傻傻的直接mod (26 ** len)了。
应该是减去 (26 ** len) 再mod (MOD).
不能mod (26 ** len)的。

The idea is similar to Lee215's post.
Using rolling hash to avoid recalculation of the hash key.
Using binary search to find the longgest length.

class Solution {
    Long MOD;
    public String longestDupSubstring(String S) {
        int N = S.length();
        int max = 0;
        String ans = "";
        MOD = 1000000007L;
        int l = 0, r = N - 1; 
        //binary search 
        
        while (l <= r) {  
            int mid = l + (r - l) / 2;          
            boolean breakout = false;
            Map> map = new HashMap<>(); // the List store a list of indexes which have the same hashCode
            long prev = 0;
            long pow26 = calcPower26(mid);
            for (int i = 0; i + mid - 1 < N; i++) {
                long code = calc(S, i, mid, prev, pow26); // calculate hashcode
                if (map.containsKey(code)) {
                    for (int m : map.get(code)) { // iterate thru the list and verify the match to deal with hash collision.
                        if (S.substring(i, i + mid).equals(S.substring(m, m + mid))) {
                            breakout = true;
                            if (mid > max) {
                                max = mid;
                                ans = S.substring(i, i + mid);
                            }
                            break;
                        }
                    }
                }
                if (breakout) break;
                map.putIfAbsent(code, new ArrayList<>());
                map.get(code).add(i);
                prev = code; //log prev for next hashcode calculation.
            }
            if (breakout) l = mid + 1;
            else r = mid - 1;
        }
        return ans;
    }
    private long calc(String s, int start, int len, long prev, long pow26) {
        long ans = 0L;
        if (start == 0) { // first time calcuation
            for (int i = 0; i < len; i++) {
                ans *= 26L;
                ans += (long) (s.charAt(start + i) - 'a');
                ans %= MOD;
            }
        } else { // defer from previous result.
            ans = prev * 26L;
            ans += (long) (s.charAt(start + len - 1) - 'a');
            ans -= (s.charAt(start - 1) - 'a') * pow26;    // 在这里写了一个bug, 我直接用ans % pow26了。
        }
        ans %= MOD;
        if (ans < 0L) ans += MOD;
        return ans;
    }
    private long calcPower26 (int n) {
        if (n == 0) return 1L;
        if (n == 1) return 26L;
        long half = calcPower26( n / 2);
        long ans = (half * half) % MOD;
        ans *= calcPower26(n - (n / 2) * 2);
        return ans % MOD;
    }
    
}

你可能感兴趣的:(1044. Longest Duplicate Substring)