题目:
给你一个字符串 s,找到 s 中最长的回文子串。
示例1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例2:
输入:s = “cbbd”
输出:“bb”
示例3:
输入:s = “a”
输出:“a”
示例4:
输入:s = “ac”
输出:“a”
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成
解题代码:
// 这个函数都能看懂
char * strSretreatment(char * s, int len){
char *str = (char *)malloc(len * sizeof(char));
memset(str, 0x0, len * sizeof(char));
str[len - 1] = '$'; // 防止越界
str[0] = '@'; // 防止越界
for(int i = 1, j = 0; i < len - 1; i++){
if(i % 2 != 0)
str[i] = '#';
else
str[i] = s[j++];
}
return str;
}
char * longestPalindrome(char * s){
if(strlen(s) == 1)
return s;
// 对字符串进行预处理
int len = 2 * strlen(s) + 3;
// 预处理字符串
char *str = strSretreatment(s, len);
// 记录字符串每个位置的回文长度
int *p = (int *)malloc(len * sizeof(int));
// 标记最长回文串的中心点
int mid = 0;
// 标记最长回文串的最右端
int right = 0;
// 最长回文串的半径
int maxLen = 0;
// 最长回文串的中心
int maxCenter = 0;
for(int i = 1; i < len - 3; i++){
/*
对我来说最难理解的地方:2*mid-i 是 i 相对于 mid 的对称点 因为是对称结构 所以p[2*mid-i] = p[i]
如果i大于以mid为中心的回文串的右边界right 那就没有对称点 所以p[i] = 1
如果p[2*mid-i] > right-i 说明只能对称到right-i的位置 所以p[i] = right - i
*/
if(i < right)
p[i] = p[2*mid-i] < (right-i) ? p[2*mid-i] : (right-i);
else
p[i] = 1;
// 以中心点向两端扩散
while(i-p[i] >= 0 && i+p[i] < len && str[i + p[i]] == str[i - p[i]]){
p[i]++;
}
// i + p[i]表示当前所求位置回文串的又边界
if(i + p[i] > right){
right = i + p[i];
mid = i;
}
//记录最长回文串的半径和中心位置
if (p[i] > maxLen) {
maxLen = p[i];
maxCenter = i;
}
}
// 原字符串中回文串起点(原字符串与预处理之后的字符串是二倍关系)
int start = (maxCenter - maxLen) / 2;
// 原字符串中回文串终点
s[start + maxLen - 1] = '\0';
s = s + start;
return s;
}
吐槽:算法是真的牛,折磨了我好几天