5.最长回文子串

题目

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

一. 中心扩张

依次遍历字符串的每个字符,然后以该字符为中心向外扩展,直到不满足回文为止,以此找出最长的子串。

js实现

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
  var len = s.length
  if (!len) {
    return s
  }
  var result = s[0]
  for (var i=0;i<len;i++) {
    // 以当前字符为中心
    var left = i
    var right = i
    while (left - 1 >= 0 && right + 1 < len) {
      if (s[left-1] === s[right+1]) {
        left--
        right++
      } else {
        break
      }
    }
    if (right + 1 - left > result.length) {
      result = s.substring(left, right+1)
    }
    // 以当前字符与下一字符之间为中心
    left = i + 1
    right = i
    while (left - 1 >= 0 && right + 1 < len) {
      if (s[left-1] === s[right+1]) {
        left--
        right++
      } else {
        break
      }
    }
    if (right + 1 - left > result.length) {
      result = s.substring(left, right+1)
    }
  }

  return result
};

复杂度分析

时间复杂度:O(n2)

空间复杂度:O(n)

测试结果

✔ Accepted
  ✔ 103/103 cases passed (80 ms)
  ✔ Your runtime beats 99.26 % of javascript submissions
  ✔ Your memory usage beats 84.53 % of javascript submissions (35.6 MB)

二. Manacher算法

在回文中,当前位置与关于对称中心的左侧位置相同,利用此性质,回文中对称位置已保存的回文半径也是当前位置的回文半径,因此,减少了判断次数,再向外扩展回文即可。

js实现

// @lc code=start
/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
  // Manacher算法

  // 使用`#`填充使其长度为奇数
  var slist = s.split('')
  var ns = '#' + slist.join('#') + '#'

  // 定义p数组
  var p = new Array(ns.length).fill(0)
  var id = 0       // 用于对称性的子串中心的下标
  var right = 0    // id子串的最右边界下标
  var reCenter = 0 // 最大回文子串中心下标
  var reLen = 0    // 最大回文子串长度

  // 开始遍历
  for (var i=0;i<ns.length;i++) {
    // 在以id为中心的回文内,当前位置和关于id对称的位置相同
    if (right > i) {
      p[i] = Math.min(right - i, p[2*id - i])
    } else {
      p[i] = 1
    }
    // 扩展回文子串
    while (i-p[i] >= 0 && ns[i+p[i]] === ns[i-p[i]]) {
      p[i]++
    }
    // 当i在id子串右边界之外时更新id子串
    if (i + p[i] > right) {
      id = i
      right = i + p[i]
    }
    // 更新结果
    if (p[i] > reLen) {
      reCenter = i
      reLen = p[i]
    }
  }
  return s.substr(Math.ceil((reCenter-reLen)/2), reLen - 1)
};

复杂度分析

时间复杂度:O(n)

空间复杂度:O(n)

测试结果

✔ Accepted
  ✔ 103/103 cases passed (84 ms)
  ✔ Your runtime beats 98.84 % of javascript submissions
  ✔ Your memory usage beats 39.05 % of javascript submissions (37.7 MB)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值