leetCode 第五题 最长回文子串
题目描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
这道题有很多种解法,但暴力法无疑时间复杂度是最高的,会超出时间限制,这里就介绍一下中心扩展法
中心扩展法
所谓中心扩展法,就是从一个中心往两边扩展判断
给定字符串s,下标i,根据中心扩展法,我们需要往两边扩展判断
left = i - 1;right = i + 1
如果s[left]等于s[right]则继续往两边扩展判断
当s[left]不等于s[right]时结束,这时候返回right-left就是回文串的长度
贴上代码
function search(s,l,r){
let left = l,
right = r;
while(left >= 0 && right < s.length && s[left] === s[right]){
left--;
right++;
}
return right - left - 1; //right - left - 2 + 1 减二是因为上一个判断循环了一次left-- 和 right++
}
由于字符串aba和abba都是回文字符串,所以这两种类型全都要判定,我们给left,right的赋值就会不同 给定字符串s,下标i,第一种回文字符串aba使left=right=i,第二种abba使left=i,right=i+1 所以每个下标要使用两次中心扩展法。
贴上代码
for(let i = 0 ; i < s.length; i++){
let len1 = search(s,i,i)
let len2 = search(s,i,i+1)
}
通过上面的代码,我们已经找出了回文串的长度,那么接下来就是怎么得到它了。我们要得出所有回文子串中最长的那一个,为了后面方便得到回文子串,定义最长回文子串的开始下标start和结束下标end,最长回文子串就是s.slice(start,end+1) 那么代码应该长这样
贴上代码
var start = end = 0
for(let i = 0 ; i < s.length; i++){
let len1 = search(s,i,i)
let len2 = search(s,i,i+1)
let len = Math.max(len1,len2)
if(len > end -start){
start = i - Math.floor((len - 1) / 2)
end = i + Math.floor(len / 2)
}
}
return s.slice(start,end+1)
这里有必要说start = i - Math.floor((len - 1) / 2);end = i + Math.floor(len / 2)是怎么得到的
-
假设坐标为i,当length为奇数时,i为中心点,取子字符串
起始坐标 i_start = i - (len-1)/2
终止坐标 i_end = i + (len-1)/2
-
假设坐标为i,当length为偶数时,i为中心前置点,取子字符串
起始坐标 i_start = i - (len)/2 - 1
终止坐标 i_end = i + (len)/2
那么整理一下就是
i_start = i - (len-1)/2 ------------ length为奇数
i_start = i - (len)/2 - 1 ------------ length为偶数
换算一下就是
i_start = i - (len-1)/2 == i - Math.floor((len-1)/2) ------------ length为奇数
i_start = i - (len)/2 - 1 == i - (len-2)/2 == i - Math.floor((len-1)/2) ------------ length为偶数
同理
i_end = i + (len-1)/2 == i + Math.floor(len / 2) ------------ length为奇数
i_end = i + (len)/2 == i + Math.floor(len / 2) ------------ length为偶数
所以给定i对于所有length的回文子串响应的起始和终止坐标
start = i - Math.floor((len - 1) / 2)
end = i + Math.floor(len / 2)
贴上所有代码
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function(s) {
var start = end = 0
for(let i = 0 ; i < s.length; i++){
let len1 = search(s,i,i)
let len2 = search(s,i,i+1)
let len = Math.max(len1,len2)
if(len > end -start){
start = i - Math.floor((len - 1) / 2)
end = i + Math.floor(len / 2)
}
}
return s.slice(start,end+1)
function search(s,l,r){
let left = l,
right = r;
while(left >= 0 && right < s.length && s[left] === s[right]){
left--;
right++;
}
return right - left - 1;
}
};