[LeetCode-JAVA] Shortest Palindrome
题目:
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.
For example:
Given "aacecaaa"
, return "aaacecaaa"
.
Given "abcd"
, return "dcbabcd"
.
题意:在原字符串的前面加上若干字母,使其形成回文,返回其中最短的。
思路1:最开始的思路,总后往前扫面,如果[o - i]可以形成回文,则将n后面的reverse并且添加到s的前面即可,这样做勉强可以AC,但显然是最差的算法。
代码1(AC时间850ms左右):
public class Solution { public String shortestPalindrome(String s) { for(int i=s.length();i>=1;i--) if(isPalindrome(s.substring(0, i))) return new StringBuilder(s.substring(i)).reverse()+s; return ""; } static boolean isPalindrome(String s){ int left=0,right=s.length()-1; while(left<right) if(s.charAt(left++)!=s.charAt(right--)) return false; return true; } }
思路2:和思路1差不太多,考虑是否可以用不同的方式进行判断,只是判断回文的方式不同,采取中心点的方式,可以作为一种想法,但效果和1差不多。
代码2(AC时间800ms左右):
public class Solution { public String shortestPalindrome(String s) { if(s == null || s.length() < 2) return s; int index = 0; for(int i = 0 ; i < s.length()*2-1 ; i++){ int left = i/2; int right = i/2; if(i%2 == 1) right++; if(helper(s, left, right)){ index = (i%2 == 1 ? right*2 : right*2+1); } } return new StringBuilder(s.substring(index)).reverse() + s; } private boolean helper(String s, int left, int right) { while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){ left--; right++; } if(left == -1) return true; return false; } }
思路3(推荐思路):利用曼彻斯特算法,其中利用dp来保存已有的结果,进行大幅度的加速。
在曼彻斯特回文判断中,加入判断,因为题目最主要是要找到包含第一个字符的回文,因此在循环的过程中,当最长子回文包含第一个字符的时候,将索引更新,最后将回文后面的部分reverse之后添加到s前面即可。
代码3(AC时间300ms左右):
public class Solution { public String shortestPalindrome(String s) { if(s == null || s.length() < 2) return s; int len = s.length(); int n = len * 2 + 3; char[] toCharry = new char[n]; toCharry[0] = '$'; toCharry[1] = '#'; for(int i = 0 ; i < s.length() ; i++){ toCharry[2*i + 2] = s.charAt(i); toCharry[2*i + 3] = '#'; } toCharry[n-1] = '!'; int[] p = new int[n]; int in = 0; int mx = 0; int maxpi = 0; int maxin = 0; for(int i = 1 ; i < n-1 ; i++){ if(i < mx) p[i] = Math.min(mx - i, p[2*in - i]); else p[i] = 1; while(toCharry[i + p[i]] == toCharry[i - p[i]]) p[i]++; if(p[i] + i > mx){ mx = i + p[i]; in = i; } if(p[i] > maxpi && in == p[in]){ maxpi = p[i]; maxin = in; } } StringBuilder sb = new StringBuilder(); for(int i = maxin+p[maxin] ; i < n-1 ; i += 2){ sb.append(toCharry[i]); } return sb.reverse() + s; } }
参考链接:http://www.felix021.com/blog/read.php?2040
http://m.blog.csdn.net/blog/xc889078/10858041