[路飞]_leetcode-647-回文子串

1,434 阅读2分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

[题目地址] [B站地址]

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

回文字符串 是正着读和倒过来读一样的字符串。

子字符串 是字符串中的由连续字符组成的一个序列。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

示例 1:

输入: s = "abc"
输出: 3
解释: 三个回文子串: "a", "b", "c"

示例 2:

输入: s = "aaa"
输出: 6
解释: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa"

提示:

  • 1 <= s.length <= 1000
  • s 由小写英文字母组成

题解1

双层循环获取所有可能的子字符串,判断是否是回文字符串

如果是回文串,结果值 res++

代码如下:

/**
 * 校验给定字符串区间是否为回文串
 * @param {string} s
 * @param {number} l
 * @param {number} r
 * @return {boolean}
 */
function check(s,l,r){
  while(l<r){
    if(s[l]!==s[r]) return false;
    else l++,r--
  }
  return true;
}

var countSubstrings = function(s) {
  const len = s.length;
  // 因为每个字符可以是回文子串,所以初始化res为len
  let res = len;
  // 判断所有可能子串是否是回文串
  for(let i = 0;i<len-1;i++){
    for(let j = i+1;j<len;j++){
      if(check(s,i,j)) res++
    }
  }
  return res;
};

以上题解提交通过后,耗时 320ms 左右,只击败了 17% 左右的用户

因为上述题解通过双层循环求得每一种子字符串,check 内层 check 函数又对该子字符进行判断是否为回文串,时间复杂度为 O(n³)

但是如果进行优化呢?

查找所有子字符串是一个必经的过程,这里只能是 O(n²) 的时间复杂度

校验每个子字符串是否是回文串,也只能是 O(n) 的时间复杂度

想了半天没有思路,于是厚着脸皮看了官方题解

题解2

官方直接跳过了获取所有子字符串的过程,直接通过中心拓展获取所有回文子串,那么中心拓展是如何做的呢?

  1. 首先会通过循环枚举所有可能的回文串的中心位置,然后判断当前左右位置的字符是否相等
  2. 如果相等,则结果值加一,左右指针继续向外拓展
  3. 如果不相等,则退出本次循环 代码如下:
var countSubstrings = function(s) {
  const n = s.length;
  let res = 0;
  // 枚举可能的回文串的中心位置,向左右扩展
  // 如果相等,则找到新的回文串,res++
  // 否则退出本次循环
  for (let i = 0; i < 2 * n - 1; i++) {
    let l = i >> 1, r = (i >> 1) + i % 2;
    while (l >= 0 && r < n && s[l] == s[r]) {
      res++,l--,r++
    }
  }
  return res;
};

以上题解提交通过后,耗时 70ms 左右,击败了 90+% 用户

至此我们就完成了 leetcode-647-回文子串

如有任何问题或建议,欢迎留言讨论!