Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.

    Example 1:

    1. Input: "aacecaaa"
    2. Output: "aaacecaaa"

    Example 2:

    1. Input: "abcd"
    2. Output: "dcbabcd"

    题意

    给定一个字符串s,要求在它前面添加字符,使得到的新字符串为回文串,且长度最短。

    思路

    在原字符串s中找到以左端点为开头的最长回文子串,将s中剩余的右半部分逆置后放在原字符串之前,得到的一定是最短的回文串,如图:
    image.png

    所以问题就转化为了找到原字符串中左侧的最长回文子串。

    常规方法用214. Shortest Palindrome (H) 待完善KMP - 图2的时间即可找到回文子串。另有两种214. Shortest Palindrome (H) 待完善KMP - 图3复杂度的方法:

    Manacher马拉车算法:具体解析详见博客园 - BIT祝威

    KMP:待完善


    代码实现 - Two Pointers

    1. class Solution {
    2. public String shortestPalindrome(String s) {
    3. int maxLength = 1;
    4. for (int i = s.length(); i >= 1; i--) {
    5. if (isPalindrome(s.substring(0, i))) {
    6. maxLength = i;
    7. break;
    8. }
    9. }
    10. StringBuilder sb = new StringBuilder();
    11. for (int i = s.length() - 1; i >= maxLength; i--) {
    12. sb.append(s.charAt(i));
    13. }
    14. sb.append(s);
    15. return sb.toString();
    16. }
    17. private boolean isPalindrome(String s) {
    18. int left = 0, right = s.length() - 1;
    19. while (left < right) {
    20. if (s.charAt(left++) != s.charAt(right--)) {
    21. return false;
    22. }
    23. }
    24. return true;
    25. }
    26. }

    代码实现 - Manacher马拉车算法

    1. class Solution {
    2. public String shortestPalindrome(String s) {
    3. int maxLen = findMaxPalinLength(s);
    4. StringBuilder sb = new StringBuilder();
    5. for (int i = s.length() - 1; i >= maxLen; i--) {
    6. sb.append(s.charAt(i));
    7. }
    8. sb.append(s);
    9. return sb.toString();
    10. }
    11. private int findMaxPalinLength(String s) {
    12. String t = transform(s);
    13. int[] p = new int[t.length()];
    14. int C = 0; // 中心位置
    15. int R = 0; // 右边界
    16. int maxLen = 0; // 回文串最大半径
    17. for (int i = 0; i < t.length(); i++) {
    18. int j = 2 * C - i; // j是i关于C的对称点
    19. p[i] = R >= i ? Math.min(p[j], R - i) : 0; // 分三种情况进行赋值
    20. // 回文半径可能增加的情况
    21. while (i + p[i] + 1 < t.length() && i - p[i] - 1 >= 0 && t.charAt(i + p[i] + 1) == t.charAt(i - p[i] - 1)) {
    22. p[i]++;
    23. }
    24. // 找到以左端点为起点的最长回文字串
    25. if (i - p[i] == 0 && p[i] > maxLen) {
    26. maxLen = p[i];
    27. }
    28. // 更新中心点和右边界
    29. if (i + p[i] > R) {
    30. C = i;
    31. R = i + p[i];
    32. }
    33. }
    34. return maxLen;
    35. }
    36. // 字符串转换
    37. private String transform(String s) {
    38. StringBuilder sb = new StringBuilder();
    39. for (int i = 0; i < s.length(); i++) {
    40. sb.append('#').append(s.charAt(i));
    41. }
    42. sb.append('#');
    43. return sb.toString();
    44. }
    45. }

    代码实现 - KMP