题目描述
给你一个字符串s,找到s中最长的回文子串。
示例
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/lo…
实现
- 基本思想:遍历字符串s,以其中的每一个字符为中心向两边发散(左右指针),如果两边的相等,则组成回文,直到遇到第一个不相等的为止。
- 由于字符串有奇数、有偶数,分开处理较为繁琐,因此在每个字符两边增加#标记,这样不论字符个数是奇数还是偶数,最后形成的字符串都是奇数。如"aba"变为"#a#b#a#,"ab"变为"#a#b#"。
- 以字符串"cbbd"为例,我们先将字符串加标记形成新的字符串"#c#b#b#d#",然后开始做如下遍历:
- #: 此时"#"自己单独形成长度为1的回文,左指针向左走到-1,右指针向右走到1位置,由于左指针走到-1,越界,不符合回文特征,因此以0位置的"#"为中心形成的最大回文字符串长度为1;
- c: 此时"c"自己单独形成长度为1的回文,左指针向左走到0位置的"#",右指针向右走到2位置的"#",相等,此时最大回文长度为3("#c#");
- ...
- d: 此时"d"自己单独形成长度为1的回文,左指针向左走到6位置的"#",右指针向右走到8位置的"#",此时最大回文长度为3("#d#"),左指针继续向左走到5位置的"b",右指针向右走到9位置越界,不符合回文特征,因此以7位置的"d"为中心形成的最大回文字符串长度为3;
- ...
// 以字符为中心向左右扩展
void GetExpendString(char *s, int len, int value, int *begin, int *end)
{
int left = value;
int right = value;
while (left >= 0 && right < len && s[left] == s[right]) {
left--;
right++;
}
*begin = left + 1;
*end = right - 1;
}
//以数组中的每个字符为中心向两边扩展,查看最长回文子串,由于字符串可能是单数或者双数,
//所以需要分开判断,不方便,因此将字符串都加上#变为单数,如abba->#a#b#b#a#
char * longestPalindrome(char * s)
{
int i = 0;
int flag = 0; // 用于去除添加的#
int begin = 0; // begin和end用于返回每一个字符可以组成的回文范围
int end = 0;
int resBegin = 0; // 保存最大回文的头和尾
int resEnd = 0;
int len = 2 * strlen(s) + 1; // 加#后构建的字符串的长度
if (s == NULL) {
return NULL;
}
if (strlen(s) == 1) {
return s;
}
// 构造新字符串,要作为结果返回,所以使用malloc分配到堆中
char *res = (char*)malloc(sizeof(char) * (2 * strlen(s) + 1)); // 加上#之后的字符串
for (i = 0; i < 2 * strlen(s) + 1; i++) {
if (i % 2 == 0) {
res[i] = '#';
} else {
res[i] = s[flag++];
}
}
// 对新字符串的每一个字符进行处理,每个字符串前后走,看是否也相等
for (i = 0; i < 2 * strlen(s) + 1; i++) {
GetExpendString(res, len, i, &begin, &end);
if (end - begin > resEnd - resBegin) {
resBegin = begin;
resEnd = end;
}
}
flag = 0;
// 去除添加的#字符串,返回结果
for (i = resBegin; i <= resEnd; i++) {
if (res[i] != '#') {
res[flag++] = res[i];
}
}
res[flag] = '\0';
return res;
}