力扣算题1——最长回文字串[双指针]
- 一、博客声明
- 二、题目描述
- 三、解题思路
- 1、思路说明
- 2、知识补充
- a、malloc动态内存分配
- b、free释放内存
- c、strlen求字符数组长度
- d、strncpy函数
- 四、解题代码(附注释)
一、博客声明
找工作逃不过刷题,为了更好的督促自己学习以及理解力扣大佬们的解题思路,开辟这个系列来记录。代码可能不是自己写的,更多的是理解大佬们的解题思路。
二、题目描述
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"
输出:"bb"
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母组成
三、解题思路
1、思路说明
这题主要使用双指针的方法来解决,以回文字的中间位置为突破口,让这两个指针在循环的时候朝着相对的方向移动,给定相应的判断条件来解决问题需求。在过程中求得最大回文字的长度以及第一个字在数组中的位置,最后用strncpy函数来返回目标回文字。
第一种情况: 如果数组的长度小于等于1,则直接返回原来的数组就可以了
第二种情况: 如果数组的长度大于1,则如下图,先用for循环遍历整个数组,在遍历数组中每个元素的时候用left和right对向移动,并同时用while循环判断s[left]
与s[right]
是否相等,若相等left--
和right--
。从对上申请两个int大小的内存,用于每次while结束后存储回文字的长度right - left - 1
,以及第一个字在数组中的位置left + 1
。在这种情况下,我们还需要考虑回文字长度是奇数还是偶数,如果是奇数的话,我们可以设置初始值left=right=i
;若为偶数,则可以left=i,right=i+1
。用len1
记录奇数情况len2
记录偶数情况。求最大的len
作为最终结果。
2、知识补充
a、malloc动态内存分配
malloc命令是从“堆”上面申请内存,内存是匿名的,类型和大小需要自己指定,返回的是指针(首指针,相当于数组第一个元素对应的地址)。申请地址的写法如下:
//从堆申请了2个int大小的内存,并把首地址给ret
int* ret = malloc(sizeof(int) * 2);
b、free释放内存
堆上面的内存大小是固定的,用完就没了,如果此时程序没有结束的话就会报错,即内存泄漏导致的溢出。这在对一些堆内容不大的嵌入式设备上编写程序时,需要特别注意。这时候就在代码末尾释放掉申请的内存就可以。比如释放上面申请的ret可以在代码末尾加上free(ret);
。子函数中要返回申请的堆内容的话,是不用释放的,在主函数释放对应的返回值就可以了。
c、strlen求字符数组长度
c语言中有一些命令可以快捷的用于开发,strlen(char*)
可以用来就一个字符数组的大小,只能求字符数组的大小,当然字符串也是字符数组。因此,题目所给的字符数组便可以用该命令来获取数组大小。
//获取字符数组的大小
int s_len = strlen(s);
d、strncpy函数
该函数的全部描述为:char *strncpy(char *dest, const char *src, size_t n)
把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。当我们知道最长回文字串的首地址和长度之后,就可以用这个库函数将其取出,进行return
。
四、解题代码(附注释)
//返回值为ret指针,ret[0]是回文字长度,ret[1]是首个字在s数组中的位置
int* lenOfPalindrome(char* s, int left, int right){
int L = left, R = right;
int* ret = malloc(sizeof(int)*2);
while(L >= 0 && R <= strlen(s) - 1 && s[L] == s[R]){
L--;
R++;
}
ret[0] = R - L - 1;//之所以是这样,是因为while循环是先判断后处理,L多减了1,R多加了1
ret[1] = L + 1;//之所以是这样,是因为while循环是先判断后处理,L多减了1
return ret;
}
char* longestPalindrome(char* s) {
if(strlen(s) <= 1) return s;//长度小于等于1,直接返回
int* len = NULL;
for(int i = 0; i < strlen(s) - 1; i++){
int* len1 = lenOfPalindrome(s, i, i);//奇数情况
int* len2 = lenOfPalindrome(s, i, i+1);//偶数情况
if(len == NULL || len1[0] > len[0]){
free(len);
len = len1;
} else {
free(len1);
}
if(len == NULL || len2[0] > len[0]){
free(len);
len = len2;
} else {
free(len2);
}
}
char* result = malloc(sizeof(char) * (len[0] + 1));//要多算一个结束符号位置
result = strncpy(result, s + len[1], len[0]);
result[len[0]] = '\0';//要加上结束符
free(len);
return result;
}