Longest Palindromic Substring

    xiaoxiao2022-06-29  28

    Question

    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.

    Quick Navigation

    SummarySolution Approach #1 (Longest Common Substring) [Accepted]Approach #2 (Brute Force) [Time Limit Exceeded]Approach #3 (Dynamic Programming) [Accepted]Approach #4 (Expand Around Center) [Accepted]Approach #5 (Manacher's Algorithm) [Accepted] 问题:求最长回文子字符串 这里介绍一下五种方法: 方法1:最长公共子字符串的方法 解决时通常会犯的一个错误解法:对于字符串S,经过反转得到S',然后求两者的公共子字符串。仅这样求解是错误的,以下是说明: 通常时,如S={c,a,b,a}和反转S'={a,b,a,c}。两个的公共子字符串是{a,b,a},它也是答案的解。但是对于一些例子,如S={a,b,a,c,d,f,g,d,c,a,b,a}和它的 反转S'={a,b,a,c,d,g,f,d,c,a,b,a},它们的公共子字符串是{a,b,a,c,d},显然它不是答案。 可见,如果S的其他部分如果等于另外某一部分的子字符串反转,那么它得到的结果将不是答案。 对此,我们可以修改原来的算法: 每次我们找到候选的最长公共子字符串,我们都要检查一下该子字符串在S中的下标是否同S'的原始下标一致。如果一致,我们就更新目前所找的最长回文字符串,如果下标有异,我们就跳过这个字符串。 算法复杂度: O ( n2 ) 方法2:暴力法(TLE) 显然,就是把所有可能的开始和结束位置组成的子字符串进行回文判断。 算法复杂度:时间复杂度O(n3),因为有(2n)=2n(n1)个字符串,每个字符串最多进行n次操作                      空间复杂度:O(1) 方法3:动态规划(AC原文是这样的,但我试的时候,TLE了,不知道是否有错误) 定义一个二维数组P[n][n],其中P[i][j]代表从i开始到j结束的子字符串是否是回文。 P(i,j)={true,if the substring SiSj is a palindromefalse,otherwise.  因此,我们得到以下递推式:            P(i,j)=(P(i+1,j1) and Si==Sj) 如果s[i]==s[j],则子字符串s[i,...,j]与子字符串s[i+1,...,j-1]的判断结果一样。 初始化时:p[i,i]=true,只有一个元素时,必是回文;两个元素时,p[i,i+1]=(s[i]==s[i+1]); 在此基础上,可以使用动态规划判断回文字符串了。 下面的代码,没有初始化两个元素的情况,但初始时如i>j,p[i,j]=true;解决了这一情况。 说明:TLE,没有通过 int n=s.size(); vector > f(n); int i,j,start,end; for(i=0;i =j) f[i][j]=true; else f[i][j]=false; int len=1; start=end=0; for(j=1;j 方法4:以中心展开(AC) 我们观察到回文都是以中心为镜像的,因此一个回文可以围绕他的中心展开,而这样的中心有2n-1个。 也许,你会问为什么是2n-1而不是n个呢?因为一个回文的中心可能会在两个字母的中间。当回文的字符个数 是偶数时,如{a,b,b,a},那么它的中心就在两个b之间。因此,对于有n个字母的字符串,它有n(n个字母) + n-1(n个字母间的n-1个间隙)=2n-1个中心。 class Solution { int expandAroundCenter(string s, int left, int right) { int L = left; int R = right; while (L >= 0 && R < s.length() && s[L]==s[R]) { L--; R++; }//循环结束时,最后边界的两个字符不再回文之内 return R - L -1;//R-L+1-2 } public: string longestPalindrome(string s) { int start = 0, end = 0; for (int i = 0; i < s.length(); i++) { int len1 = expandAroundCenter(s, i, i); int len2 = expandAroundCenter(s, i, i + 1); int len = max(len1, len2); if (len > end - start) { start = i - (len - 1) / 2; end = i + len / 2; } } string str(s,start,end-start+1); return str; } }; 算法复杂度分析:时间复杂度O(n*n),空间复杂度O(1) 方法5:Manacher算法 时间复杂度O(n),技巧性很强,不太懂 string preProcess(string s) { int n = s.size(); if (n == 0) return "^$"; string ret = "^"; for (int i = 0; i < n; i++) { ret += "#"; ret+=s[i]; } ret += "#$"; return ret; } public: string longestPalindrome(string s) { string T = preProcess(s); int n = T.size(); vector P(n); //int *P = new int[n]; int C = 0, R = 0; for (int i = 1; i < n-1; i++) { int i_mirror = 2*C-i; // equals to i' = C - (i-C) P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0; // Attempt to expand palindrome centered at i while (T[i + 1 + P[i]] == T[i - 1 - P[i]]) P[i]++; // If palindrome centered at i expand past R, // adjust center based on expanded palindrome. if (i + P[i] > R) { C = i; R = i + P[i]; } } // Find the maximum element in P. int maxLen = 0; int centerIndex = 0; for (int i = 1; i < n-1; i++) { if (P[i] > maxLen) { maxLen = P[i]; centerIndex = i; } } //delete[] P; string str(s,(centerIndex - 1 - maxLen)/2,maxLen); return str; //return s.substr((centerIndex - 1 - maxLen)/2, maxLen); } http://articles.leetcode.com/longest-palindromic-substring-part-ii/
    转载请注明原文地址: https://ju.6miu.com/read-1125018.html

    最新回复(0)