Manacher 算法算法比较复杂,不考虑,我们只学习中心扩散算法和DP
也就是枚举每个点,找到最长的回文串。回文串分为两种:奇数和偶数长度的回文串。其中奇数的串是关于中心对称的,偶数的串是左右相同。
因为要求最长的回文子串,但是我们并不清楚最长的回文子串的长度是奇数还是偶数,所以要覆盖两种情况。
题目中的数据长度范围都是1000比较小,这种方法的时间复杂度是O(n2)的所以可以通过。
https://leetcode-cn.com/problems/longest-palindromic-substring/solution/cdong-tai-gui-hua-by-ye-ao-nai-wo-he-1-tpdy/
法一、中心扩散法
1 class Solution { 2 public: 3 string longestPalindrome(string s) { 4 string res; 5 6 //枚举每个中心点 7 for(int i = 0;i < s.size();i++){ 8 9 //假设回文串的长度为奇数 10 int l = i - 1,r = i + 1; 11 while( l >= 0 && r < s.size() && s[l] == s[r]){ 12 l--,r++; 13 } 14 if(res.size() < (r -1) - (l + 1) + 1) res = s.substr(l+1,r-l-1); 15 16 //假设回文串的长度为偶数 17 l = i,r = i + 1; 18 while(l >= 0 && r <s.size() && s[l] == s[r]){ 19 l--,r++; 20 } 21 if(res.size() < (r -1) - (l + 1) + 1) res = s.substr(l+1,r-l-1); 22 } 23 24 return res; 25 } 26 };
法二、动态规划
1 class Solution { 2 public: 3 string longestPalindrome(string s) { 4 if(s.size() < 2) return s; 5 6 int max_len = 1; 7 int start = 0; 8 //二位dp数组,用来存放[i,j]是否是回文子串,如果是就为1,否则为0 9 vector<vector<int>>dp(s.size(),vector<int>(s.size())); 10 11 //dp数组初始化,单个长度的子串一定是回文子串 12 for(int i = 0;i < s.size();i++){ 13 dp[i][i] = 1; 14 } 15 16 for(int len = 2;len <= s.size();len++){ 17 for(int i = 0;i < s.size();i++){ 18 19 int j = len + i -1; 20 //j为终点的下标,其中len = j - i + 1 21 22 23 if(j > s.size() - 1) break; //j的右侧极限 24 25 if(s[i] != s[j]) dp[i][j] = 0; 26 else{ 27 if(len == 2) dp[i][j] = 1; //长度为2,肯定是回文串 28 else dp[i][j] = dp[i+1][j-1]; 29 //长度>2,需要看[i+1,j-1]是否为回文串 30 } 31 32 if(dp[i][j] && len > max_len){ 33 max_len = len; 34 start = i; 35 } 36 37 38 39 } 40 } 41 42 return s.substr(start,max_len); 43 } 44 };
本题不论是中心扩散法还是动态规划算法时间复杂度都为O(n2),区别在于中心扩散算法的空间复杂度为O(1),动态规划算法的空间复杂度为O(n2),要存储一个DP数组。