问题描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
题解
方法一、暴力法
利用循环遍历所有子串,并判断是否为回文
function longestPalindrome(s) {
let isPlalindrome = (str) => {
for(let i = 0, length = Math.floor(str.length / 2); i < length; i++){
if (str.charAt(i) !== str.charAt(str.length - i -1)) {
return false
}
}
return true
}
let str1, result, len = 0
if (!s) return s
for (let i = 0, length = s.length; i < length; i++) {
for (let j = i + 1; j < length + 1; j++) {
str1 = s.substring(i, j)
if (isPlalindrome(str1)) {
if (j - i > len ) {
result = str1
len = j - i
}
}
}
}
return result
}
方法二、最大公共子串
将字符串反转与原字符串比较,求出最大公共子串,注意’adcwecda’,反转之后公共子串不是回文。
function longestPalindrome2(s) {
let arr = [], maxLen = 0, end = 0
let s1 = s.split('').reverse().join('')
for(let i = 0, length = s.length; i < length; i++) {
for(let j = 0; j < length; j++) {
// 将二维数组的每一项设为数组
if (j == 0) arr[i] = []
if (s.charAt(i) == s1.charAt(j)) {
if (i == 0 || j == 0) {
arr[i][j] = 1
} else {
arr[i][j] = arr[i-1][j-1] + 1
}
} else {
arr[i][j] = 0
}
if (maxLen < arr[i][j]) {
// 比较倒置前后坐标是否对应
let indexRev = length - j - 1
if (indexRev + arr[i][j] - 1 == i) {
end = i
maxLen = arr[i][j]
}
}
}
}
return s.substring(end -maxLen + 1, end +1)
}
算法图解:
方法三、扩展中心法
一个字符串其中可以有
2n - 1
个扩展中心, 通过不断移动中心并进行扩展,判断是否为回文,从而取得最大长度的回文子串
var longestPalindrome = function(s) {
if (s.length < 1) return ''
let expandAroundCenter = (left, right) => {
while (left >= 0 && right < s.length && s.charAt(left) == s.charAt(right)){
left --
right ++
}
return right - left - 1
}
let start = 0, end = 0
for(let i = 0, length = s.length; i < length; i++) {
const len1 = expandAroundCenter(i, i)
const len2 = expandAroundCenter(i, i+1)
const max = Math.max(len1, len2)
if (max > end - start) {
start = i - ((max - 1) >> 1)
end = i + (max >> 1)
// 或
// start = i - Math.floor((max - 1) / 2)
// end = i + Math.floor(max / 2)
}
}
return s.substring(start,end+1)
};