这里主要是记录一些我做这个题遇到的问题及解决办法
1.问题描述
1.1 思路分析:
对于个题目而言,我使用的均是中心扩散法,但是细节处理有些不同,有两个版本,一个是字符串原地返回,另外一个是申请内存并进行保持符合要求的字符串,然后进行返回;
总体而言,就是分为两种情况,而且两种情况均进行遍历,第一种就是类似"abacd"
的情况,遍历到b
时,以其为中心向两边扩散,直到两边不相等,另外一种是abccbd
,那么遍历到第一个c
时,就不能以c为中心向两边遍历看看是否相等,也就是偶数情况,这时要把left
指向第一个c
,把right
指向第二c
,然后进行判断。
!!!
如果只按照上面的思路进行写程序,会显得很麻烦,很多细节要考虑到,因此可以选择暴力一点,对每一个字符,我们都认为它既是奇数类又是偶数类,对一个字符进行两次遍历,按照奇数遍历一次,按照偶数遍历一次
,那么虽然增加了重复度,但是写代码时思路会大大清晰
2.程序代码及注释:
2.1 方法1–申请内存-中心扩散
方法1-申请内存-中心扩散-两种方式均遍历
一些细节
首先对于申请的内存: 要进行初始化,而且要有字符串结尾符’\0’,不然会出现堆栈错误的提示,编译不通过;
char* res = (char*)malloc(sizeof(char) * 10001);
res[0] = s[0];
res[1]='\0';
char* longestPalindrome(char* s) {
int len = strlen(s);
int i, j, k, left, right, max, flag;
int ll, rr;
char mid;
char* res = (char*)malloc(sizeof(char) * 10001);
res[0] = s[0];
res[1]='\0';
max = 0;
left = 0;
right = 0;
k = 0;
if (len <= 1) {
return s;
}
for (i = 0; i < len; i++) // 循环遍历完整个字符串,每个字符都要确定一下
{
//奇数情况
left = i - 1;
right = i + 1;
while (left >= 0 && right < len && s[left] == s[right]) {
if (max < (right - left + 1)) {
max = right - left + 1;
ll = left;
rr = right;
}
left--;
right++;
}
//偶数情况
left = i;
right = i + 1;
while (left >= 0 && right < len && s[left] == s[right]) {
if (max < (right - left + 1)) {
max = right - left + 1;
ll = left;
rr = right;
}
left--;
right++;
}
//把符合要求的值给存储起来
for (j = ll; j <= rr; j++) {
res[k] = s[j];
k++;
res[k] = '\0';
}
k = 0;
}
return res;
}
2.1 方法2-中心扩散法+字符串原地返回
方法1-申请内存-中心扩散-两种方式均遍历
一些细节
首先对于max = 1
;//思考为什么是1?不是0?这个问题比较简单,对于字符串"ab"而言,循环中不会进行判断,也就是max的值不会更新,所以返回s时第二个值要截断成’\0’,所以要max预设成1;
其次对于s[max] = '\0';//思考为什么是max,不是rr+1,或者right??
;这个问题我也是没有发现,首先可以排除right,因为right最大会增加到len,也就是超出了数组的边界,所以先排除right。但是程序中:rr和max是同时增加的,而且数组的长度是[ll,rr]
闭区间下标对应的值,所以截断符\0
理所当然的截到rr+1
,这时很理所当然的,我当时也是这样认为的,但是结果是错误的!
if (max < (right - left + 1))
{
max = right - left + 1;//max和rr是同时增加的
ll = left;
rr = right;
}
错误的原因
:
这个错误的原因是后的语句顺序,首先思想是正确的,但是这时建立在s
不变的基础上,但是后面的语句是这样的:
/*错误语句*/
s = s + ll;//先修改s
s[rr+1] = '\0';//再截断s
上面先改变了s的起始位置,然后再截断,这样明显是错误的,实际修改这样就对了:
s[rr+1] = '\0';//先截断s
s = s + ll;//在修改s
上面的顺序就是正确的。
而对于max而言,其一直记录的就是整个最大长度,结果都是不发生改变的,其书写顺序应该按照下列这样
s = s + ll;//先修改s
s[max] = '\0';//再截断s
如果写成这样的顺序就是错误的:
/*错误语句*/
s[max] = '\0';//先截断s
s = s + ll;//再修改s
如果理解不了,可以用一个例制:“cbbd”,当循环结束时,rr=2,ll=1,max=2;
- 如果先修改s=s+ll,那么说s=“bbd",此时再截断应该使用的是s[max]或者s[rr]
- 如果先截断s,那么就是s[max+1]=‘\0’,或者s[rr+1]=‘\0’,此时s=“cbb”,然后修改s,也就是s=s+ll;
char* longestPalindrome(char* s) {
int len = strlen(s);
int i, j,left, right, max;
int ll, rr;
max = 1;//思考为什么是1?不是0?
left = 0;
right = 0;
ll=0;
rr=0;
if (len <= 1) {
return s;
}
for (i = 0; i < len; i++) // 循环遍历完整个字符串,每个字符都要确定一下
{
left = i - 1;
right = i + 1;
while (left >= 0 && right < len && s[left] == s[right]) {
if (max < (right - left + 1)) {
max = right - left + 1;
ll = left;
rr = right;
}
left--;
right++;
}
left = i;
right = i + 1;
while (left >= 0 && right < len && s[left] == s[right]) {
if (max < (right - left + 1)) {
max = right - left + 1;
ll = left;
rr = right;
}
left--;
right++;
}
}
s = s + ll;
s[max] = '\0';//思考为什么是max,不是rr,或者right??
return s;
}