214. Shortest Palindrome


July-14-2019
还是挺难的,又过了一遍KMP.

最直接的办法是楞做。
abcd = > bcd abcd
aacecaaa => a aacecaaa
说白了就是找到给定String里面longest palindrome prefix。
怎么找呢? 最直观的做法就是左右同时往中间,扫到相遇说明本身就是plindrome。
失败的话,去掉右边最后一位, 重新扫,就是aacecaaa =>去掉最后一个A,继续扫 aacecaa然后发现满足。 这么做时间就爆炸了。

一个稍微好点的办法是

    public String shortestPalindrome(String s) {
        if (s.length() <= 1) return s;
        
        int l = 0;
     
        for (int r = s.length() - 1; r >= 0; r --) {
            if (s.charAt(r) == s.charAt(l)) {
                l ++;
            }
        }
        if (l == s.length()) return s;
        
        return new StringBuilder(s.substring(l)).reverse().toString() + shortestPalindrome(s.substring(0, l)) + s.substring(l);
    }
}

失败之后,继续,最后3个位置 0 - l - end来说,l-end肯定不符合规矩,需要翻转加到最前面,0-l不确定,只知道longest prefix palindrome肯定在这里面,所以继续recursively call。 其实这个也不好理解,我大概的理解是,每个LR的mismatch会让l最终到END的距离+1.

刚才说道KMP,

palindrome + something = S,我们要找的就是longest palindrome
assuming palindrome of S = S·
palindrome + something + something· + palindrome· = SS·
palindrome = palindrome·
这个问题变成了求SS·的最长 前缀=后缀,就是KMP的next[]干的事。
不同的一点是,KMP里的NEXT可以让前缀后缀有overlap,比如aaaaa的最长前缀=后缀是aaaa而不是aa
所以得保证我们generate KMP next[]的时候最长不能超过一半,有2个办法,一个是在SS`中间加个不存在与S中的字符,类似于S + "&" + S·这样每次OVERLAP都肯定会FAIL
另一个办法是每次到了超过一半的位置就reset J,比较难理解,得深刻想明白为什么NEXT要那样GENERATE出来才能理解。

class Solution {
    public String shortestPalindrome(String s) {
        if (s.length() <= 1) return s;
        
        int[] kmp = generateKmp(s + new StringBuilder(s).reverse().toString());
        
        int index = kmp[kmp.length - 1];

        return new StringBuilder(s.substring(index)).reverse().toString() + s;
        
    }
    
    public int[] generateKmp(String s) {
        if (s == null) return null;
        int[] res = new int[s.length()];
        
        int j = 0;
        for (int i = 1; i < s.length(); i ++) {
            if (i == s.length() / 2) j = 0;
            while (j != 0 && s.charAt(i) != s.charAt(j)) {
                j = res[j - 1];
            }
            
            if (s.charAt(i) == s.charAt(j)) {
                j ++;
            }
            
            res[i] = j;
        }
        return res;
    }
}
原文地址:https://www.cnblogs.com/reboot329/p/6060573.html