回文子串(力扣第647题)

题目

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

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

示例

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

分析

​ 因为求的是回文子串的个数,而单个字符构成的子串都可以认为是回文串,所以一个给定的字符串,其最少拥有len(str)个回文子串。同时,如果多个回文子串的字符和顺序完全相同,但是其开始位置或者结束位置不同,那么也不认为这些回文子串是同一个。

​ 我最先想到的方法是暴力破解,即先定义一个判断一个字符串是否是回文串的函数,然后遍历字符串的所有子串逐个判断。该方法的时间复杂度为O(n!),时间性能和空间性能都不算优秀。

    public int countSubstrings(String s) {

        StringBuilder new_s = new StringBuilder(s);
        int res = 0;

        for (int i = 0; i < s.length(); i++) {

            for (int j = i + 1; j <= s.length() ; j++) {

                if (isHui(s.substring(i,j))){
                    res++;
                }
            }
        }

        return res;
    }

    private boolean isHui(String s){

        StringBuilder rev_s = new StringBuilder(s).reverse();

        if (s.equals(rev_s.toString())){
            return true;
        }

        return false;
    }

​ 为此,需要想出一个更加优化的算法来解决这一问题。可以从字符串的某一个字符位置处向外扩展,扩展的方式分别是奇数扩展和偶数扩展两种方式,即分别求奇数长度和偶数长度的回文子串。这样就能大大缩短查询时间,时间复杂度为O(nlogn)。

    private int cnt = 0;
    public int countSubstrings(String s) {
        for (int i = 0; i < s.length(); i++) {
            extendSubstrings(s, i, i);     // 奇数长度
            extendSubstrings(s, i, i + 1); // 偶数长度
        }
        return cnt;
    }

    private void extendSubstrings(String s, int start, int end) {
        while (start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)) 	   {
            start--;
            end++;
            cnt++;
        }
    }

参考:

https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode 题解 - 字符串.md#3-字符串中单词的翻转

原文地址:https://www.cnblogs.com/yxym2016/p/13984956.html