给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
示例 1:
输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd" 输出: "bb"
来源于LeetCode
可以直接跳过我写的代码,看大佬的代码,毕竟我写的代码太垃圾了!!!
最近做题的最大感触就是太依赖于其他的数据结构作为存储,然后使用它们的方法操作,比如数组的push,pop,还要对象作为存储,有时候还要删除对象里的某个属性,这样做大大的降低了性能,时间和内存消耗都是非常严重的,就是这样所以第一和第三题就不敢发出来。虽然今天的第五题内存消耗和时耗也不低,但是,我再贴一个LeetCode的题解里面大神的代码,这样比较更能让我在刷题的时候提示自己,不能过多的借用其他数据结构。
首先这题我的想法是
1.遍历s字符串
2.以每个字符为中心扩散判断是否有回文数
但是这要分为两种情况: 1.回文数是abba类型的,也就是说回文数的长度是偶数
2.回文数是aba类型的,回文数的长度的奇数
因此每个字符要判断这两种情况(说实话这种想法有点糟糕,每个字符判断两种情况,而且还不算这个字符在两边扩散时候的情况,这也是消耗时间的,虽然很耗时,但是还是写下来,留给以后的自己看,不要再像这样了)
3.无论是奇数类型(arr2)的回文数还是偶数类型(arr1)的回文数都放入数组中,然后判断这两个数组到底哪个长,把长的赋给arr1
4.判断result的长度和arr1的长度 , 把最长的赋给result(说实话太麻烦了)
5.继续将中心转移到下一个字符
回文数是abba类型的
self表示所在的字符的索引 , left表示所在字符索引的左边。right表示在右边, length1表示在偶数方法的长度
arr1 = []; //表示记录偶数字符串的
arr2 = []; //表示记录奇数字符串的
length1 = 0;//偶数字符的长度初始值
left = right = self; //最开始的时候left和right都指向self
right ++; //首先判断的是偶数情况,所以是应该要从两个字符向周围扩展,即 self 和self+1扩展
while (s[left] == s[right] && left >= 0 && right < s.length) {//第一种情况,最长回文数是abba类型长度是偶数
arr1.unshift(s[left]);//将左和右加入到arr1的数组中
arr1.push(s[right]);
right++; //向两边扩散,在判断左右两边是否有相同的字符,持续下去直到没有相同的
left--;
length1 += 2;//回文数的数量每次成对出现
}
奇数类型的
left = self - 1;//重新将left和right置位
right = self + 1;
length2 = 1; //因为奇数个的时候,所在的中心是回文数最中间的,所以直接将他的长度置为1,并且加入到arr2数组中
arr2.push(s[self]);
while (s[left] == s[right] && left >= 0 && right < s.length) { //和偶数的一样扩散
arr2.unshift(s[left]);
arr2.push(s[right]);
right++;
left--;
length2 += 2;
}
全部代码
var longestPalindrome = function (s) {
let left, right, length1, length2, self = 1, result = [], arr1 , arr2;
while (self < s.length) {
arr1 = [];
arr2 = [];
length1 = 0;
left = right = self;
right ++;
while (s[left] == s[right] && left >= 0 && right < s.length) {//第一种情况,最长回文数是abba类型长度是偶数的
// console.log(s[left] + ' ' +s[right])
arr1.unshift(s[left]);
arr1.push(s[right]);
right++;
left--;
length1 += 2;//回文数的数量每次成对出现
}
// console.log(arr1)
//把left和right归位,判断是否有aba这种单数的
left = self - 1;
right = self + 1;
length2 = 1;
arr2.push(s[self]);
while (s[left] == s[right] && left >= 0 && right < s.length) {
arr2.unshift(s[left]);
arr2.push(s[right]);
right++;
left--;
length2 += 2;
// console.log('我执行额' + length2 +' ' + self)
}
// console.log(length1 + ' ' + length2)
arr1 = arr1.length > arr2.length ? arr1 : arr2;
result = arr1.length > result.length ? arr1 : result;
self ++;
}
return result.join('');
};
大佬的代码(用c写的)
介绍一下大佬的思路
首先连续重复的字符一定能构成回文子串 ,如aaabb('aaa' , ‘bb’) cdbbbbdbv('bbbb')
只要我们记住重复的字符串的开始和结尾,再以最后一个重复的字符为重心扩展 ,如aaabb , 记住第一个a的初始位置
char * longestPalindrome(char * s){
int left = 0;
int right = 0;
int maxLength = 0; //回文子串最大长度
int startIndex = 0; //最长回文子串开始位置
int index = 0;
while(s[index]){
right=index;
left=index-1;
//从当前字符开始往右读取连续重复字符(连续重复字符必定能构成回文子串,也必定是回文子串的一部分)
//如"abcccd" 中从索引1开始的连续重复字符是"b",从索引2开始连续重复字符是'ccc'
while(s[right]==s[index]){
right++;
}
//定位下一个子串的中心
index = right;
//以连续重复字符为中心,往左右延展,判断当前子串是否为回文子串
while(left >= 0 && s[right] && s[left]==s[right]){
left--;
right++;
}
//记录回文子串的最大长度和起始索引
if(right-left-1>maxLength){
startIndex = left+1;
maxLength = right-left-1;
}
}
//返回回文子串
char* returnStr = (char*)malloc(maxLength+1);
returnStr[maxLength]='\0';
for(int i=0;i<maxLength;i++){
returnStr[i]=s[startIndex+i];
}
return returnStr;
}