[菜鸟训练]647. 回文子串

这篇博客介绍了如何计算字符串中的回文子串数量,提供了中心扩展和动态规划两种解决方案。中心扩展方法通过遍历所有可能的回文中心并扩展检查是否为回文,时间复杂度为O(n^2),空间复杂度为O(1)。动态规划方法使用二维布尔数组记录子串是否为回文,同样时间复杂度为O(n^2),但空间复杂度提高到O(n^2)。代码示例展示了这两种方法的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

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

示例 1:
输入:“abc”
输出:3
解释:三个回文子串: “a”, “b”, “c”

示例 2:
输入:“aaa”
输出:6
解释:6个回文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”

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

代码:

public class LC647 {
    //中心扩展,时间复杂度O(n^2) 空间复杂度O(1) 不如dp好理解
    public int countSubstrings(String s) {
        int len = s.length();
        int ans = 0;
        //长度为n的字符串会生成2n-1组回文中心
        //我们只需要将这些回文中心遍历一遍,然后把奇数长度和偶数长度两种情况统一起来即可
        for (int i = 0; i < 2 * len - 1; i++){
            int l = i / 2,r = i / 2 + i%2;
            while (l >=0 && r < len && s.charAt(l) == s.charAt(r)){
                --l;
                ++r;
                ++ans;
            }
        }
        return ans;
    }

    //dp,时间复杂度O(n^2) 空间复杂度O(n^2)
    public int countSubstrings1(String s){
        //用来存取该字符串中的区间为[i,j]的子串是否是回文串,是的话为true,不是为false
        //那么我们最后只需要遍历其全部有可能的区间,然后判断其为false还是true即可
        //最后统计dp数组中true的个数,即就是我们要找的回文子串个数
        boolean[][] dp = new boolean[s.length() + 10][s.length() + 10];
        int ans = 0;

        //为什么这里我们第一层循环要倒着呢?
        //因为我们的状态转移方程为:dp[i][j] = j-i<=2 || dp[i + 1][j - 1]
        //如果正着来,我们求dp[i][j]的时候就需要知道dp[i + 1][j - 1],但此时dp[i + 1][j - 1]的结果我们还没有得到
        for (int i = s.length() - 1; i >= 0; i--){
            for (int j = i; j < s.length(); j++){
                //区间左右端点不同,一定不是回文
                if (s.charAt(i) != s.charAt(j))
                    continue;
                //动态转移方程
                if (j - i <= 2 || dp[i + 1][j - 1]){
                    dp[i][j] = true;
                }
                //统计是回文的个数
                if (dp[i][j]){
                    ans++;
                }
            }
        }
        return ans;
    }

    public static void main(String[] args) {
        LC647 obj = new LC647();
        System.out.println(obj.countSubstrings1("abc"));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值