最长回文子串问题解法
暴力求解
找出所有子串,依次判断是不是回文子串即可,时间复杂度n^3,大概率导致一些测试点超时。
中心扩展法
依次将每一个位置作为中心,向两侧扩展,直到不满足回文条件位置,找出最大的长度。
但是要注意每个位置要考虑两种情况:
所以每个位置需要按照两种方式分别进行扩展
时间复杂度n^2
动态规划算法
状态转移方程
dp[i,j]=
- dp[i+1,j-1],str[i]=str[j]
- 0,str[i]!=str[j]
其中dp[j][j]==1
含义为从i到j的子串为回文子串
int dp(string s) { int n = s.size(); if (n < 1) { return n; } int longest = 1; int start = 0; vector<vector<int>> dp(n, vector<int>(n)); for (int i = 0; i < n; i++) { dp[i][i] = 1; if (i < n - 1) { if (s[i] == s[i + 1]) { dp[i][i + 1] = 1; start = i; longest = 2; } } } for (int l = 3; l <= n; l++) { for (int i = 0; i < n - l + 1; i++) { int j = l + i - 1; if (s[i] == s[j] && dp[i + 1][j - 1] == 1) { dp[i][j] = 1; start = i; longest = l; } } } return longest; }
|
马拉车算法
- 将字符串扩展为奇数位,每两个字符之间插入一个#,并在首位插入两个不一样的其他字符,来防止越界如
abc
可变为$#a#b#c#^
- 进行马拉车算法,思路参考了知乎Manacher算法
int Manacher(string s) { s = preProcess(s); vector<int> p(s.size(), 0); int center = 0, right = 0; for (int i = 1; i < s.size() - 1; i++) { int i_mirror = 2 * center - i; if (right > i) { p[i] = min(right - i, p[i_mirror]); } else { p[i] = 0; } while (s[i + 1 + p[i]] == s[i - 1 - p[i]]) { p[i]++; } if (i + p[i] > right) { center = i; right = i + p[i]; } } return *max_element(p.begin(), p.end()); }
|
整体代码
#include <bits/stdc++.h>
using namespace std;
string preProcess(string s) { int n = s.length(); string temp = "^"; if (n == 0) { temp += "$"; return temp; } for (int i = 0; i < n; i++) {
temp += "#"; temp += s[i]; } temp += "#$"; return temp; }
int Manacher(string s) { s = preProcess(s); vector<int> p(s.size(), 0); int center = 0, right = 0; for (int i = 1; i < s.size() - 1; i++) { int i_mirror = 2 * center - i; if (right > i) { p[i] = min(right - i, p[i_mirror]); } else { p[i] = 0; } while (s[i + 1 + p[i]] == s[i - 1 - p[i]]) { p[i]++; } if (i + p[i] > right) { center = i; right = i + p[i]; } } return *max_element(p.begin(), p.end()); }
int dp(string s) { int n = s.size(); if (n < 1) { return n; } int longest = 1; int start = 0; vector<vector<int>> dp(n, vector<int>(n)); for (int i = 0; i < n; i++) { dp[i][i] = 1; if (i < n - 1) { if (s[i] == s[i + 1]) { dp[i][i + 1] = 1; start = i; longest = 2; } } } for (int l = 3; l <= n; l++) { for (int i = 0; i < n - l + 1; i++) { int j = l + i - 1; if (s[i] == s[j] && dp[i + 1][j - 1] == 1) { dp[i][j] = 1; start = i; longest = l; } } } return longest; } int main() { string a; getline(cin, a); cout << dp(a); }
|