算法刷题:回文子串

139 阅读2分钟

题目描述

给定一个字符串,你的任务是计算这个字符串中有多少个回文字串。

  • 具有不同开始位置或者结束位置的字串,即使是由相同的字符组成,也会被视作不同的子串。
  • 回文字符串 是正着读和倒过来读一样的字符串。
  • 子字符串 是字符串中的由连续字符组成的一个序列。
  • 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

示例1

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

示例2

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

提示:输入的字符串长度不超过1000

解法一:暴力法
let countSubStrings = function(s){
    let count = 0
    for(let i=0;i<s.length;i++){
        for(let j=i;j<s.length;j++){
            // 判断是否是回文子串
            if(isPalindrome(s.substring(i, j+1))){
                count++
            }
        }
    }
    return count
}
// 回文串首尾字符相同,且剩余子串也是一个回文串
let isPalindrome = function(s){
    let i=0,j=s.length-1
    while(i<j){
        if(s[i] != s[j]) return false
        i++
        j--
    }
    return true
}

复杂度分析:

  • 时间复杂度:O(n^3)
  • 空间复杂度O(1)

解法:动态规划

1、分析题意

一个字符串是回文串,它的首尾字符相同,且剩余子串也是一个回文串。

其中剩余子串是否为回文串是一个子问题,它的结果影响大问题的结果。

如何来描述子问题呢?

显然,一个子串由两端的子i\j指针确定,就是描述子问题的变量,子串si...j是否是回文串,就是子问题。

let countSubstrings = function(s){
    const len = s.length
    let count = 0
    const dp = new Array(len)
    
    for(let j=0;j<len;j++){
        for(let i=0;i<=j;i++){
            // 表示竖表已经走完
            if(s[i] = s[j] && (j-i<=1 || dp[i+1])){
                dp[i] = true
                count++
            }else{
                dp[i] = false
            }
        }
    }
    return count
}

复杂度分析:

  • 时间复杂度:O(n^2)
  • 空间复杂度O(n)