这是我参与更文挑战的第11天,活动详情查看: 更文挑战
题目描述
最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
leetcode-cn.com/problems/lo…
// 示例1
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
// 示例2
输入:s = "cbbd"
输出:"bb"
// 示例3
输入:s = "a"
输出:"a"
// 示例4
输入:s = "ac"
输出:"a"
标签
中心扩散法
解题分析
1. 中心扩散法
看到了一种解题思路很牛逼,我们用这种思路来解一下题目。
回文串(palindromic string)是指这个字符串无论从左读还是从右读,所读的顺序是一样的;简而言之,回文串是左右对称的。所谓最长回文子串问题,是指对于一个给定的母串
中心扩散法,顾名思义把字符串中的每一个字符都当做中心,然后根据判断条件来处理是否向左右两侧继续扩散。
我们把中心扩散法带入到题目当中。
假设传入的字符串string为 abcacdc。
暂时保存的回文子串为 res 为 '' (空字符串)
其实我们可以肉眼看出 最长的回文子串为 cac。
它是怎么得出的,我们用中心扩散法一步步看下去。
由于回文子串的中心有奇数和偶数两种类型,我们下面的代码也会检测两种。
对于可以扩散的条件为
1. start >= 0 左侧扩散 如果扩散到0 也就是第一个字符,就可以结束了
2. end < s.length 右侧扩散 与上同理 如果扩散到字符串尾部,就可以结束了
3. s[start] === s[end] 因为他是回文子串,以中心来看,慢慢扩散出去,左右肯定是相等的 cabac
第一个字符 a
以 奇数 看待 当前遍历字符:a
我们扩散第一次:
左侧到底,扩散结束,
接着判断是否大于保存的回文子串res, 由于此时res为空,那么 res = 'a'
以 偶数 看待 当前遍历字符:ab
同上,由于条件3,两个字符串不想等 那就不扩散了
接着判断在start end边界内的字符串 这时为空,那就直接跳过
....
第4个字符 a
以奇数看待, 当前遍历字符: a
扩散第一次:
左侧右侧都可以扩散,同时扩散取到的至 start是'c',end也是'c',满足条件 继续扩散
扩散第二次:
左右两侧可以扩散,但是扩散到的值start是'b',end也是'd', 不满足条件,就不扩散了。
然后比对长度是否比之前存储的res长,如果长那继续保存
最后 res= 'cac' 也就是最长的回文子串。
function longestPalindrome(s: string): string {
if(s.length < 2) return s
let res = ''
for(let i=0; i< s.length; i++) {
//如果回文子串为奇数 那么传入的长度为 i到i 那就是一个字符
// abcba 回文子串中心为c 扩散到左右
getString(i, i)
//如果回文子串为偶数,那么传入的长度为 i到i+1 那就是两个字符
// abccba 回文子串中心为cc 扩散到左右
getString(i, i+1)
}
function getString (start: number, end: number): void {
// 这里一步步看
// 在这里,把每个传入的 s.splice(start, end)字符串当成中心来看,每次扩散左右,来判断左右是否是相等的
// 1. start >= 0 左侧扩散 如果扩散到0 也就是第一个字符,就可以结束了
// 2. end < s.length 右侧扩散 与上同理 如果扩散到字符串尾部,就可以结束了
// 3. s[start] === s[end] 因为他是回文子串,以中心来看,慢慢扩散出去,左右肯定是相等的 cabac
while(start >= 0 && end < s.length && s[start] == s[end]) {
start--
end++
}
// 到这里的代码有两种结果
// 1. 第一种 左侧右侧扩散到底了
// 2. 第二种 扩散左右的值不想等
// 所以这里的字符串肯定是回文子串,然后题目需要最长的,需要比对每次记录的回文子串,拿最大的出来。
if(end - start - 1 > res.length) {
res = s.slice(start + 1, end)
}
}
return res
};
最后
从今天开始不鸽,每天一道算法题并发布文章,首先想要解决的题组为Top100,第二道题目打完收工!!