首页 > 技术文章 > 【LeetCode-字符串】回文子串

flix 2020-04-30 17:37 原文

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
示例:

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

输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".

题目链接: https://leetcode-cn.com/problems/palindromic-substrings/

思路1

暴力法来做。计算出所有的子字符串,然后判断子字符串是回文串的个数。代码如下:

class Solution {
public:
    int countSubstrings(string s) {
        if(s.length()==1) return 1;

        string ss = "";
        int cnt = 0;
        for(int i=0; i<s.length(); i++){
            for(int j=1; j<=s.length()-i; j++){
                ss = s.substr(i, j);
                if(isOk(ss)) cnt++;
            }
        }
        return cnt;
    }

    bool isOk(string s){
        int left = 0, right = s.length()-1;
        while(left<right){
            if(s[left]!=s[right]) return false;
            left++;
            right--;
        }
        return true;
    }
};
// 超时
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

该方法超时未通过。

思路2

如果一个串是回文串,那么从该回文串中心从两边扩展,两边的字符也是相等的。如果字符串的长度为奇数,例如aba,从b开始设置两个指针向两边扩展就可以判断出aba是一个回文串;如果字符串的长度为奇数,例如abba,如果两个指针的起始位置相同的话,是不会得出abba是一个回文串的,在这种情况下,两个指针的起始位置需要相差一位,例如将指针left指向第一个b,将指针right指向第二个b,这样其实就是把bb这个整体作为中心向两边扩展。假设字符串的长度为n,单个字符为中心有n个中心,两个字符为中心有n-1个中心,所以总的中心个数为2n-1。所以,算法的过程为:遍历整个字符串,记录以当前以当前字符为中心和以当前字符以及当前字符的下一个字符为中心的回文串个数。
代码如下:

class Solution {
public:
    int countSubstrings(string s) {
        if(s.length()==1) return 1;
        
        int n = s.length();
        int cnt = 0;
        for(int center=0; center<2*n-1; center++){
            int left = center/2;
            int right = left+center%2;

            while(left>=0 && right<n && s[left]==s[right]){
                cnt++;
                left--;
                right++;
            }
        }
        return cnt;
    }
};
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

总结

遇到与回文串相关的题目时,可以考虑使用“中心扩展法”。

相关题目

1、最长回文子串:https://www.cnblogs.com/flix/p/12692867.html

推荐阅读