【力扣】5. 最长回文子串 - 力扣(LeetCode)

这里主要是记录一些我做这个题遇到的问题及解决办法

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;
}
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值