题目
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
复制代码
思路
- 暴力法。2层循环嵌套,遍历所有子串。在判断子串是否为回文并对比保存最大的起止下标。通过前后同时截取字符串对比的方式来判断子串是否为回文。如果相等,就向两边靠拢,直对比的下标相等并且值也相等位置。如果不相等,子串非回文。
- 中心扩展算法。回文字符串有一个特点,就是左右对称。如果是奇数长度的回文字符串,中间的字符作为对称点,如aba中的a。如果是偶数长度的回文字符串,会以中间两个字符作为对称点,如abba中的bb。那么比较的时候,找到中心点,两边扩展对比就可以了。直到打破对称,通过暂存的历史最长回文子串的起止坐标比对当前长度,如果当前子串的长度较大,更新起止坐标。由于存在奇偶两种长度,对应的中心点不一样,但两种模式都可能产生回问子串,所有匹配的时候两种模式都要进行匹配,并取同一个中心点的两种模式中长度更长的更新起止坐标,这个是编码时需要处理的细节问题。
编码细节问题
1.为了获取最后的子串,需要通过暂存起止坐标startIndex、endIndex。 2.默认奇数匹配方式,通过判断当前元素与其后面的元素是否相等来决定是否满足偶数匹配。
char* longestPalindrome(char* s) {
int startIndex = 0 ;
int endIndex = 0;
int len = strlen(s);
for (int i = 0; i < len; i ++) {
int frontIndex = i ;
int nextIndex = i;
bool evenSerech = true;
//满足偶数匹配方式
if (s[i] == s[nextIndex + 1]) {
evenSerech = true;
}
while (frontIndex > -1 && nextIndex < len && s[frontIndex] == s[nextIndex]) {
frontIndex --;
nextIndex ++;
}
int current = --nextIndex + 1 - ++frontIndex ;
if (current > (endIndex + 1 - startIndex)) {
startIndex = frontIndex;
endIndex = nextIndex;
}
if (evenSerech) {
frontIndex = i ;
nextIndex = i + 1;
while (frontIndex > -1 && nextIndex < len && s[frontIndex] == s[nextIndex]) {
frontIndex --;
nextIndex ++;
}
int current = --nextIndex + 1 - ++frontIndex ;
if (current > (endIndex + 1 - startIndex)) {
startIndex = frontIndex;
endIndex = nextIndex;
}
}
}
char *p = (char*)malloc(sizeof(char*) * (endIndex + 1 - startIndex));
int j = 0;
for (int i = startIndex; i <= endIndex; i ++) {
p[j ++] = s[i];
}
return p;
}
复制代码
小结:需要认真的分析回文的特点,回文串分偶数长度与奇数长度两种情况(认真审题并分析题目所求,不能忽略了一些必要的点,这一点很重要,卡时间比较多的是想通过修改起止指针的位置来适配偶数的模式,发现怎么都不能同时适配奇偶两种情况,如果是两类情况不能简单的统一处理的话,要变回单独处理)。另外这题能反转字符串取相同子串的方法(有坑)、动态规划和Manacher 算法来处理,后面再学习学习。
待完善L('ω')┘三└('ω')」....