算法题之回文子串

回文子串

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

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

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

示例 1:

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

示例 2:

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

提示:

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

解题思路

从题意可以知道,回文字符串的特点是左右两边的字符镜像对称。

我们可以遍历字符串s,然后以遍历当前的字符为中心点,比较左右两边的字符串是否相同,如果相同的话,记录答案,然后再分别向左右两边延伸继续比较,直到到达边界或者字符不相同位置。但是有个问题,就是这个方法是以字符串s的某个字符为中心的;如果是aa这样的子字符串,需要以aa中间作为中心,然后向两边延伸比较的,那怎么定位呢?

我们假设在字符串s每个字符的两侧,都插入一个特殊字符,使得我们每次遍历的时候,都可以以新的字符串中的每个字符作为中心点,这样就方便遍历了。

但是需要注意的是,由于我们插入了n + 1个特殊字符,所以遍历得到的答案是变多了的。我们需要找出得到的结果和最后结果之间的函数映射规律。

我们遍历是从原字符串的第一个字符开始,然后到最后一个节点结束:

  • 原字符串是a,填充后是#a#,得到的结果是2,真实结果是1
  • 原字符串是aa,填充后是#a#a#,得到的结果是7,真实结果是3
  • 原字符串是aaa,填充后是#a#a#a#,得到的结果是14,真实结果是6
  • 原字符串是aaaa,填充后是#a#a#a#a#,得到的结果是23,真实结果是10

 根据推断,得到的结果res和真实结果f(n)之间的规律是:

f(n)=(res+1-n)/2

其中n是原字符串的长度。

具体的代码如下所示:

class Solution {
    public int countSubstrings(String s) {
        int n = s.length();
        int ans = 0;
        StringBuffer t = new StringBuffer("#");
        for (int i = 0; i < n; i++) {
            t.append(s.charAt(i));
            t.append('#');
        }

        String s2 = t.toString();
        n = s2.length();
        
        for (int i = 1; i < n - 1; i++) {
            int l = i, r = i;
            while (l >= 0 && r < n && s2.charAt(l) == s2.charAt(r)) {
                --l;
                ++r;
                ++ans;
            }
        }
        return (ans + 1 - s.length()) / 2;
    }
}

复杂度分析

  • 时间复杂度:O(n^{2}),遍历了一遍数组s2,并且有对比左右字符延伸的操作。
  • 空间复杂度:O(n),额外创建了一个数组s2。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值