回文字符串:若一个字符串的逆置与它本身相同,这个字符串就是个回文字符串。
例:“”,“aa”,“b”,“aba”,“assbbssa”,“asdfdsa”
一个空字符串是回文的,单个字符的字符串也是回文的。
在给定字符串中查找回文子串的时候,可以以两字符和三字符的回文子串为基础,逐渐向两边扩展,直到不满足回文字符串的性质或者触碰到字符串边界为止,用这种方式来查找所有的回文子串,并给出最长的那一个。这种查找方法的最坏时间复杂的为O(n),最坏情况发生在字符串仅包含同一个字符的情况下。
#include <iostream>
using namespace std;
class Palindrome {
public:
int boundary[2] = {0, 0}; //保存回文子串的边界下标
//给定一个回文子串,以此子串为中心向两边扩展,试图查找最长的回文子串
int* findBoundary(string s, int begin, int end){
//记录字串边界
boundary[0] = begin;
boundary[1] = end;
for(int i = 1;;i++){
//当子串某一边的边界与母串重合,或者子串两端的字符不相等时,直接返回上次记录的字串边界
if(begin - i < 0 || end + i > s.length() - 1 || s[begin-i] != s[end+i]){
return boundary;
}
//子串两端的字符相等,更新边界值
boundary[0] = begin - i;
boundary[1] = end + i;
}
}
string longestPalindrome(string s) {
int n = s.length();
//空字符串或者单字符串的最长回文子串就是它本身
if(n == 1 || n == 0){
return s;
}
//双字符的字符串,若两个字符相等,最长回文子串就是它本身,否则就是它的任意一个单字符
if(n == 2){
return (s[0] == s[1])?s:s.substr(0,1);
}
int len = 1; //保存当前找到的最长回文子串的长度
string result; //保存结果
int* p = nullptr; //保存边界数组
//先判断最后两个元素能否构成回文串
if(s[n-1] == s[n-2]){
len = 2;
result = s.substr(n-2,2);
}else{
result = s.substr(0,1);
}
for(int i = 0; i < n-2; i++){
//若两个相邻字符相等,以它们为最小回文子串向两边扩展
if(s[i] == s[i+1]){
p = findBoundary(s, i, i+1);
//如果新的字串长度大于当前找到的最长回文子串的长度,更新len和result
if(*(p+1) - *p + 1 > len){
len = *(p+1) - *p + 1;
result = s.substr(*p, len);
}
}
//若三个字符串的两端相等,以它们为最小回文子串向两边扩展
if(s[i] == s[i+2]){
p = findBoundary(s, i, i+2);
//如果新的字串长度大于当前找到的最长回文子串的长度,更新len和result
if(*(p+1) - *p + 1 > len){
len = *(p+1) - *p + 1;
result = s.substr(*p, len);
}
}
}
return result;
}
};
int main() {
string s;
cin >> s;
string ret = Palindrome().longestPalindrome(s);
return 0;
}
版权声明:本文为sinat_40224875原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。