Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
- 最长回文子串-难度中等
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。 示例 2:
输入:s = "cbbd" 输出:"bb"
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母组成
二、题目和思路分析:
看到这个问题,我的第一反应是:回文字符串,即正反看起来都一样的字符串,这道题和上次做的寻找最长子串的问题很类似。
所以只要找最长子串的同时,判断该子串是否是回文字符串即可。
想着比较简单,当我按着上次做的寻找最长子串的做法再来一次的时候,来来回回报了好几个错,i和j写错了,声明的j写成了i,或者没考虑一个字符的情况,或者判断非回文的情况赋值错了。总之就是过于粗心大意,考虑不周到。
最后这些小毛病总算全部改完了,却发现提交提示【超出时间限制】,本地测了一下,很长的字符串要三秒多钟,看来暴力破解实在是走不通啊!!!
说起来也是,算法题理应尽可能地解出最优解,虽然我前面几道题也几乎都是暴力破解的。
那么是不是还有其他方式来判断回文呢?
从中位数分割字符串,这样只要判断分割的前一半翻转值是否等于分割的后一半即可,从翻转对比的角度来说,少了一半的运算量,这样总能行了吧!
然而,我还是考虑不周,字符的长度没有考虑进去,截取的下标误减去1,导致提交得到的结果仍然是错误的。最终改完这些小错误,却发现提交还是提示【超出时间限制】。
啊啊啊啊,这道题怎么这么麻烦!!!
于是我开始反思,双重的for循环可能是不对的。还有没有其它方法呢?
这时候我想到,如果只是遍历当前字符字符串,默认值初始取第一个字符,判断当前遍历的字符前后两项是否相等,如果相等则赋给默认值,继续判断默认值的前后两项,如此循环即可。
这么想着,我写出了代码,结果发现,当回文字符串长度为偶数时,结果是错误的。
因为以遍历字符的形式,判断不出偶数形式的回文数,也就是要根据偶数的回文数,即回文中间的部分是否相等来添加判断。
这一版终于改成功了~
是不是还要优化的空间呢?我想了又想,如果当前的子串长度超过字符串的一半,还不是回文子串,那么就没必要再对该子串进行累加了。
所以我又改了一版,结果是:错误的!!!
也就是说整个字符串都可能是回文字符串,所以没有做额外判断的时候,一定要判断到最后一位才可以。
三、代码:
代码实现如下:
/**
* @param {string} s
* @return {string}
*/
// 第一版
// var longestPalindrome = function(s) {
// let ss = '' // 默认最长回文子串
// if (!s) return ''
// if (s.length == 1) return s
// let length, s2, s3, a
// for(let i = 0; i < s.length; i++){
// let s1 = s[i] // 初始值
// !ss? ss = s1 : ss
// for(let j = i+1; j < s.length; j++){
// s1 += s[j]
// // 回文的判断方法修改
// // 取数组
// length = s1.length
// if(length == 2){
// s1[0] == s1[1] && ss.length < length && (ss = s1)
// }else{
// if(length % 2 == 1){ // 是奇数
// a = (length-1)/2 // 中位数
// s2 = s1.slice(0, a)
// s3 = s1.slice(a+1)
// }else{
// a = length/2
// s2 = s1.slice(0, a)
// s3 = s1.slice(a)
// }
// if([...s2].reverse().join("") == s3){
// ss.length < length? ss = s1 : ss
// }else{
// if(s1.length > (s.length/2)){
// break
// }
// }
// }
// }
// }
// if(s.length)
// return ss
// };
var longestPalindrome = function(s) {
let ss = '', s1 = ''
for(let i = 0; i<s.length; i++){
// console.log(`当前是for循环的第${i}次`)
if(s[i] == s[i+1]){
s1 = s[i] + s[i]
let uu = i-1
let oo = i+2
while(s[uu] !== void(0) && s[oo] !== void(0) && s[uu] === s[oo]){
// console.log(`当前while循环,u是${uu},o是${oo}`)
s1 = s[uu] + s1 + s[oo]
--uu
++oo
}
}
let u = i-1
let o = i+1
s1 = s[i]
while(s[u] !== void(0) && s[o] !== void(0) && s[u] === s[o]){
// console.log(`当前while循环,u是${u},o是${o}`)
s1 = s[u] + s1 + s[o]
--u
++o
}
ss.length < s1.length? ss = s1 : ss
// console.log(`第${i}次循环,s1=${s1},ss=${ss}`)
}
return ss
}
四、总结:
今天这道题目费了很长时间,原先看到题目的时候,我觉得特别简单,却没想到在这花了几个小时的时间,最开始是想的思路错了,做了双重for循环,后面是思路对了,但是判断条件弯弯绕绕,整体把握有失误。
有了正确的思路,还要快速写出正确的代码,加油吧!
加油吧!