[LeetCode] Longest Palindromic Substring 最长回文子串
2014-04-23 14:16
561 查看
最长回文子串的问题有很多变种,先看最基本的:
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.
思路: 用一个指针从0遍历到s.length()-1,从里向外来检测子串是否是回文,分两种情况:1)bab, 2)bb。也就是当前指针可能指向的是奇数回文,也可能是偶数回文。做两次检测。
Java
其他思路:
思路1. 动态规划
这里动态规划的思路是 dp[i][j] 表示的是 从i 到 j 的字串,是否是回文串。
则根据回文的规则我们可以知道:
如果s[i] == s[j] 那么是否是回文决定于 dp[i+1][ j - 1]
当 s[i] != s[j] 的时候, dp[i][j] 直接就是 false。
动态规划的进行是按照字符串的长度从1 到 n推进的。
代码很明晰:给出java代码,复杂度 O(n^2)
[java] view plaincopy
思路2. KMP匹配
第二个思路来源于字符串匹配,最长回文串有如下性质:
对于串S, 假设它的 Reverse是 S', 那么S的最长回文串是 S 和 S' 的最长公共字串。
例如 S = abcddca, S' = acddcba, S和S'的最长公共字串是 cddc 也是S的最长回文字串。
如果S‘是 模式串,我们可以对S’的所有后缀枚举(S0, S1, S2, Sn) 然后用每个后缀和S匹配,寻找最长的匹配前缀。
例如当前枚举是 S0 = acddcba 最长匹配前缀是 a
S1 = cddcba 最长匹配前缀是 cddc
S2 = ddcba 最长匹配前缀是 ddc
当然这个过程可以做适当剪枝,如果当前枚举的后缀长度,小于当前找到的最长匹配,则直接跳过。
Java 代码如下:
[java] view plaincopy
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.
思路: 用一个指针从0遍历到s.length()-1,从里向外来检测子串是否是回文,分两种情况:1)bab, 2)bb。也就是当前指针可能指向的是奇数回文,也可能是偶数回文。做两次检测。
Java
public static String longestPalindrome(String s) { if (s == null || s.length() <= 1) return s; String longestPalindrome = ""; for (int i = 0; i < s.length() - 1; i++) { String palindrome = getLongestPalindrome(s, i, i); //case: bab if (palindrome.length() > longestPalindrome.length()) { longestPalindrome = palindrome; } palindrome = getLongestPalindrome(s, i, i + 1); //case: bb if (palindrome.length() > longestPalindrome.length()) { longestPalindrome = palindrome; } } return longestPalindrome; } public static String getLongestPalindrome(String s, int left, int right) { int length = s.length(); while(left >= 0 && right < length && s.charAt(left) == s.charAt(right)) { left--; right++; } return s.substring(left + 1, right); } public static void main(String[] args){ System.out.println(longestPalindrome("wfacabcdcbagggafd")); } }
其他思路:
思路1. 动态规划
这里动态规划的思路是 dp[i][j] 表示的是 从i 到 j 的字串,是否是回文串。
则根据回文的规则我们可以知道:
如果s[i] == s[j] 那么是否是回文决定于 dp[i+1][ j - 1]
当 s[i] != s[j] 的时候, dp[i][j] 直接就是 false。
动态规划的进行是按照字符串的长度从1 到 n推进的。
代码很明晰:给出java代码,复杂度 O(n^2)
[java] view plaincopy
public class DPSolution { boolean[][] dp; public String longestPalindrome(String s) { if(s.length() == 0) { return ""; } if(s.length() == 1) { return s; } dp = new boolean[s.length()][s.length()]; int i,j; for( i = 0; i < s.length(); i++) { for( j = 0; j < s.length(); j++) { if(i >= j) { dp[i][j] = true; //当i == j 的时候,只有一个字符的字符串; 当 i > j 认为是空串,也是回文 } else { dp[i][j] = false; //其他情况都初始化成不是回文 } } } int k; int maxLen = 1; int rf = 0, rt = 0; for( k = 1; k < s.length(); k++) { for( i = 0; k + i < s.length(); i++) { j = i + k; if(s.charAt(i) != s.charAt(j)) //对字符串 s[i....j] 如果 s[i] != s[j] 那么不是回文 { dp[i][j] = false; } else //如果s[i] == s[j] 回文性质由 s[i+1][j-1] 决定 { dp[i][j] = dp[i+1][j-1]; if(dp[i][j]) { if(k + 1 > maxLen) { maxLen = k + 1; rf = i; rt = j; } } } } } return s.substring(rf, rt+1); } }
思路2. KMP匹配
第二个思路来源于字符串匹配,最长回文串有如下性质:
对于串S, 假设它的 Reverse是 S', 那么S的最长回文串是 S 和 S' 的最长公共字串。
例如 S = abcddca, S' = acddcba, S和S'的最长公共字串是 cddc 也是S的最长回文字串。
如果S‘是 模式串,我们可以对S’的所有后缀枚举(S0, S1, S2, Sn) 然后用每个后缀和S匹配,寻找最长的匹配前缀。
例如当前枚举是 S0 = acddcba 最长匹配前缀是 a
S1 = cddcba 最长匹配前缀是 cddc
S2 = ddcba 最长匹配前缀是 ddc
当然这个过程可以做适当剪枝,如果当前枚举的后缀长度,小于当前找到的最长匹配,则直接跳过。
Java 代码如下:
[java] view plaincopy
public class Solution { private int[] next; private void GetNext(String s) //KMP求next数组 { int i,j; i = 0; j = -1; next[0] = -1; while( i < s.length()) { if( j == -1 || s.charAt(i) == s.charAt(j)) { i++; j++; next[i] = j; } else { j = next[j]; } } } private int compare(String pattern, String s) //用KMP算法做求出最长的前缀匹配 { int i,j; i = 0; j = 0; int maxLen = 0; while( i < s.length()) { if(j == -1 || pattern.charAt(j) == s.charAt(i)) { i++; j++; } else { j = next[j]; } if( j > maxLen) { maxLen = j; } if(j == pattern.length()) { return maxLen; } } return maxLen; } public String longestPalindrome(String s) // { // Start typing your Java solution below // DO NOT write main() function String reverString = new StringBuilder(s).reverse().toString(); //求得到 输入string 的reverse next = new int[s.length() + 1]; String maxPal = ""; int maxLen = 0; int len; for(int i = 0; i < s.length(); i++) //枚举所有后缀 { String suffix = reverString.substring(i); if(suffix.length() < maxLen) { break; } GetNext(suffix); len = compare(suffix, s); if( len > maxLen) { maxPal = suffix.substring(0, len); maxLen = len; } } return maxPal; } }
相关文章推荐
- LeetCode 5 Longest Palindromic Substring(最长回文子串,暴力剪枝/DP/曼彻斯特算法)
- leetcode--Longest Palindromic Substring--最长回文子串--
- LeetCode 5. Longest Palindromic Substring(最长回文子串)
- 【LeetCode】Longest Palindromic Substring && 【九度】题目1528:最长回文子串(腾讯2013年实习生招聘二面面试题)
- [LeetCode]—Longest Palindromic Substring 最长回文子串
- LeetCodeOJ_5_m_Longest Palindromic Substring(最长回文子串)
- 【LeetCode-面试算法经典-Java实现】【005-Longest Palindromic Substring(最长回文子串)】
- leetcode5-Longest Palindromic Substring(最长回文子串)
- leetcode(5)—— Longest Palindromic Substring(最长回文子串)
- 最长回文子串-LeetCode 5 Longest Palindromic Substring
- LeetCode---5. Longest Palindromic Substring(最长回文子串)
- LeetCode Longest Palindromic Substring(最长回文子串)
- LeetCode:Longest Palindromic Substring 最长回文子串
- LeetCode | Longest Palindromic Substring(最长回文子串)
- leetcode-5. Longest Palindromic Substring(寻找最长回文子串)
- leetcode Longest Palindromic Substring最长回文子串
- [C++]LeetCode 5: Longest Palindromic Substring(最长回文子串)
- LeetCode-5 Longest Palindromic Substring(求最长回文子串)
- Leetcode: 5 Longest Palindromic Substring 最长回文子串
- leetcode (5) - Longest Palindromic Substring 最长回文子串