点击上方蓝字关注我,我们一起学编程欢迎小伙伴们分享、转载、私信、赞赏
最长回文子串
1. 暴力枚举法2. 中心扩展法3. 动态规划法4. Manacher 算法
所谓回文串,就是正序和逆序都相同的子串。(上海自来水来自海上)子串是原字符串的连续部分,这区别于子序列。
1. 暴力枚举法
时间复杂度:O(n^3)
空间复杂度:O(1)
class Solution {
public:
string longestPalindrome(string s){
int len = s.size();
if (len <= 1) {
return s;
}
int maxLen = 1; /* 回文串的最大长度 */
int begin = 0; /* 回文串的起始下标 */
for (int i = 0; i 1; ++i) {
/* 从大于最大长度的位置开始遍历 */
for (int j = i + maxLen ; j if (isPalindrome(s, i, j)) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxLen);
}
/* 判断是否为回文串 */
bool isPalindrome(const string& s, int start, int end){
bool ispalindrome = true;
while (start if (s[start++] != s[end--]) {
ispalindrome = false;
break;
}
}
return ispalindrome;
}
};
2. 中心扩展法
分析:
枚举所有可能的回文子串的中心位置,中心位置可能是一个字符(奇数长度),也可能是两个相邻的字符(偶数长度)。
时间复杂度:O(n^2)
空间复杂度:O(1)
class Solution {
public:
string longestPalindrome(string s){
int len = s.size();
if (len <= 1) {
return s;
}
int maxLen = 1; /* 回文串的最大长度 */
int begin = 0; /* 回文串的起始下标 */
for (int i = 0; i 1; ++i) {
int oddLen = expandAroundCenter(s, i, i); /* 回文串的中心为单个字符 */
int evenLen = expandAroundCenter(s, i, i + 1); /* 回文串的中心为两个相邻的字符 */
int curMaxLen = max(oddLen, evenLen);
if (curMaxLen > maxLen) {
maxLen = curMaxLen;
begin = i - (maxLen - 1) / 2; /* 计算当前最大回文串的起始下标 */
}
}
return s.substr(begin, maxLen);
}
/* 从中心往两边扩展,寻找最长回文子串的长度 */
int expandAroundCenter(const string& s, int left, int right){
int len = s.size();
int i = left;
int j = right;
while (i >= 0 && j if (s[i] == s[j]) {
--i;
++j;
} else {
break;
}
}
return j - i - 1;
}
};
3. 动态规划法
分析:
状态:dp[i][j]
表示子串 s[i...j]
是否为回文子串;
状态转移方程:dp[i][j] = (s[i] == s[j]) && dp[i + 1][j - 1]
;
初始化:dp[i][i] = true
;
输出:在得到一个状态的值为 true
的时候,记录起始位置和长度,填表完成以后再截取。
时间复杂度:O(n^2)
空间复杂度:O(n^2)
class Solution {
public:
string longestPalindrome(string s){
int len = s.size();
if (len <= 1) {
return s;
}
int maxLen = 1; /* 回文串的最大长度 */
int begin = 0; /* 回文串的起始下标 */
vector<vector<bool>> dp(len, vector<bool>(len, true));
for (int j = 1; j for (int i = 0; i if (s[i] != s[j]) {
dp[i][j] = false;
} else {
dp[i][j] = (j - i <= 2) ? true : dp[i + 1][j - 1];
}
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxLen);
}
};
4. Manacher 算法
时间复杂度为 O(n)
。该算法十分复杂,有兴趣的童鞋可以自己查阅相关资料。
长按识别关注
*编程笔记本*
来都来了,点个在看再走吧~~~