问题描述 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://leetcode.com/problems/longest-palindromic-substring/
DP解法 注意回文串有两种形式:a和aa,也就是中轴是一个元素或者两个元素。 可以转化为求解s和s逆序(例如dabcbaee和eeabcbad)的最长公共子串,并且这两个子串在原串中是相邻的,(例如abcjiecba中,abc和cba虽然最长公共子串,但并不相邻)
dp[i][j]表示以s以i结尾,s逆序(s’)以j结尾的两个字符串的最长公共子串的长度。可以得到递推式: dp[i][j] = dp[i-1][j-1] + 1 (if s[i]===s’[j]) dp[i][j] = 0 (if s[i] !== s’[j])
判断相邻的条件:(i + j - dp[i][j] + 1 === len) || (i + j - dp[i][j] === len)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 var longestPalindrome = function (s ) { var len = s.length , max=0 , end; var dp = []; for (var i=0 ; i<=len; i++) { dp[i] = []; dp[i][0 ] = 0 ; dp[0 ][i] = 0 ; } for (var i=1 ; i<=len; i++) { for (var j=1 ; j<=len; j++) { if (s[i-1 ] === s[len-j]) { dp[i][j] = dp[i-1 ][j-1 ] + 1 ; if (dp[i][j] > max) { if ((i + j - dp[i][j] + 1 === len) || (i + j - dp[i][j] === len)) { max=dp[i][j]; end = i; } } } else { dp[i][j] = 0 ; } } } return s.substring (end - max, end); };
这个算法的时间复杂度为O(n^2),空间复杂度为O(n^2)。后面的Manacher算法可以将时间和空间复杂度降低为O(n)。
Manacher算法 例子:dabcbaee
1.加入# 目的:这样可以简化问题,把aaa和aaaa这两种类型的回文串,变为同一种以单一元素为轴的对称。
#d#a#b#c#b#a#e#e#
2.计算可以扩展长度的向量
#d#a#b#c#b#a#e#e# [1, 2, 1, 2, 1, 2, 1, 6, 1, 2, 1, 2, 1, 2, 3, 2, 1]
3.计算时候可以利用回文串的性质进行优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 var longestPalindrome = function (s ) { var s2 = '#' ; for (var i=0 ; i<s.length ; i++) { s2 += s[i] + '#' ; } var sl = [1 ], max = 0 , id = 0 , maxid = 0 ; for (var i = 1 ; i < s2.length ; i++) { var cnt = 1 ; if (i < max) { var pilot = id * 2 - i; cnt = sl[pilot] < max - i + 1 ? sl[pilot] : max - i + 1 ; } var tp=i-cnt, tn=i+cnt; while (tp >= 0 && tn < s2.length && s2[tp] === s2[tn]) { cnt ++; tp --; tn ++; } sl[i] = cnt; if (i + cnt - 1 > max) { max = i + cnt - 1 ; id = i; if (sl[i] > sl[maxid]) { maxid = i; } } } var start = Math .floor ((maxid - sl[maxid] + 1 ) / 2 ); return s.substring (start, start + sl[maxid] - 1 ); };