Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
https://oj.leetcode.com/problems/longest-palindromic-substring/
思路1(naive approach):依次检查所有的子串(n^2),判断是否是palindrome(n),复杂度 O(n^3)。
思路2(dp):dp[i][j] 代表从i到j的子串是否是palindrome。自下而上自左而右计算dp数组。时空复杂度都是 O(n^2)。
dp[i][j]=1 if:
- i=j;
- s.charAt(i)==s.charAt(j) && j-i<2
- s.charAt(i)==s.charAt(j) && dp[i+1][j-1]==1
思路3:遍历字符串的每个字符,从这个字符出发(或者这个字符和下一个字符出发)向两侧辐射找出最长的子串。时间复杂度 O(n^2),空间复杂度O(1)。
思路4:Manacher's algorithm。时空复杂度O(n)。
http://www.felix021.com/blog/read.php?2040
DP代码:
public class Solution { public String longestPalindrome(String s) { if (s == null || s.length() == 0) return null; int start = 0; int end = 0; int len = 0; boolean[][] dp = new boolean[s.length()][s.length()]; for (int i = s.length() - 1; i >= 0; i--) { for (int j = i; j < s.length(); j++) { if (i == j || (s.charAt(i) == s.charAt(j) && j - i < 2) || (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1])) { dp[i][j] = true; if (j - i + 1 > len) { len = j - i; start = i; end = j + 1; } } } } return s.substring(start, end); } public static void main(String[] args) { System.out.println(new Solution().longestPalindrome("ababadccd")); System.out.println(new Solution().longestPalindrome("a")); System.out.println(new Solution().longestPalindrome("")); } }
第二遍记录:注意dp的状态及转移函数。
public class Solution { public String longestPalindrome(String s) { if(s==null||s.length()==0) return ""; int len=-1,start=0,end=0; boolean[][] dp = new boolean[s.length()][s.length()]; for(int i=s.length()-1;i>=0;i--){ for(int j=i;j<s.length();j++){ if(i==j||(s.charAt(i)==s.charAt(j)&&(j-i<=2||dp[i+1][j-1]))){ dp[i][j]=true; if(j-i>len){ start=i; end=j; len=j-i; } } } } return s.substring(start,end+1); } }
补思路3代码:
注意向外扩展有两种情况。
注意每次匹配向外匹配时长度增加2。
public class Solution { public String longestPalindrome(String s) { if (s == null || s.length() <= 1) return s; int n = s.length(); int maxLen = 0; String res = ""; int tmpLen = 0; for (int i = 0; i < n - 1; i++) { tmpLen = getPalin(s, i); if (tmpLen > maxLen) { maxLen = tmpLen; res = s.substring(i - (tmpLen - 1) / 2, i - (tmpLen - 1) / 2 + tmpLen); } tmpLen = getPalin(s, i, i + 1); if (tmpLen > maxLen) { maxLen = tmpLen; res = s.substring(i - (tmpLen / 2 - 1), i - (tmpLen / 2 - 1) + tmpLen); } } return res; } private int getPalin(String s, int idx) { int len = 1; int i = idx - 1, j = idx + 1; while (i >= 0 && j < s.length()) { if (s.charAt(i) == s.charAt(j)) { len += 2; i--; j++; } else break; } return len; } private int getPalin(String s, int idx, int idy) { int len = 0; int i = idx, j = idy; while (i >= 0 && j < s.length()) { if (s.charAt(i) == s.charAt(j)) { len += 2; i--; j++; } else break; } return len; } public static void main(String[] args) { System.out.println(new Solution().longestPalindrome("abccba")); } }
思路4代码:
注意开头结尾的符号不要设成一样
public class Solution { public String longestPalindrome(String s) { if (s == null || s.length() == 0) return ""; int n = s.length(); // preprocess the string StringBuilder sb = new StringBuilder(); sb.append("$#"); for (int i = 0; i < n; i++) { sb.append(s.charAt(i)); sb.append('#'); } sb.append('*'); s = sb.toString(); n = s.length(); // System.out.println(s); int mx = 0, id = 0; int[] p = new int[n]; int res = 0; int resIdx = -1; for (int i = 1; i < n - 1; i++) { p[i] = mx > i ? Math.min(p[2 * id - i], mx - i) : 1; while (s.charAt(i + p[i]) == s.charAt(i - p[i])) p[i]++; // update mx and id if (i + p[i] > mx) { mx = i + p[i]; id = i; } // record the max of p[i]; if (p[i] > res) { res = p[i]; resIdx = i; } } // construct the result string String resStr = s.substring(resIdx - (res - 1), resIdx + (res - 1) + 1); StringBuilder sb2 = new StringBuilder(); for (int i = 0; i < resStr.length(); i++) if (resStr.charAt(i) != '#') sb2.append(resStr.charAt(i)); resStr = sb2.toString(); return resStr; } public static void main(String[] args) { System.out.println(new Solution().longestPalindrome("12212321")); } }
参考:
http://www.programcreek.com/2013/12/leetcode-solution-of-longest-palindromic-substring-java/