leetcode:迴文子串

題目來源:力扣

題目介紹:

給定一個字符串,你的任務是計算這個字符串中有多少個迴文子串。
具有不同開始位置或結束位置的子串,即使是由相同的字符組成,也會被計爲是不同的子串。
=============================================================
示例 1:
輸入: “abc”
輸出: 3
解釋: 三個迴文子串: “a”, “b”, “c”.
示例 2:
輸入: “aaa”
輸出: 6
說明: 6個迴文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”.
注意:
輸入的字符串長度不會超過1000。
===========================================================

審題:

初看這道題, 我在考慮如果已知了子串S[i, j]中迴文子串的個數, 如何推導子串S[i, j+1]中迴文子串的個數. 在考慮這個方法時, 我發現我們需要知道子串S[i, j]是否爲迴文字符串, 才能進行上述分析. 而如果我們知道了子串S[i,j]是否是迴文字符串, 那麼我們可以遍歷所有子串, 然後統計迴文子串個數即可. 因此, 我將思路轉化爲判斷子串S[i, j]是否是迴文子串.

這個問題這樣一來還是比較簡單的. 如果S(i) == S(j), 則我們僅需知道子串S(i+1, j-1)是否是迴文字符串即可, 如果S(i) != S(j), 則子串S[i, j]不是迴文子串. 由於存在子問題重疊, 基於此, 我們可以使用動態規劃方法求解.

判斷每一子串是否是迴文字符串

class Solution {
    public int countSubstrings(String s) {
        boolean[][] isHuiWen = new boolean[s.length()][s.length()+1];
        //判斷當前子串[i, j]是否是迴文字符串
        for(int i = 0; i < s.length(); i++){
            isHuiWen[i][i] = true; //空串
            isHuiWen[i][i+1] = true; //單字符
        }

        for(int len = 2; len <= s.length(); len++){
            for(int left = 0;  left <= s.length()-len; left++){
                int right = left + len;
                if(s.charAt(left) == s.charAt(right-1))
                    isHuiWen[left][right] = isHuiWen[left+1][right-1];
                else
                    isHuiWen[left][right] = false;
            }
        }

        int total = 0;
        for(int i = 0; i < s.length(); i++){
            for(int j = i+1; j <= s.length(); j++){
                if(isHuiWen[i][j])
                    total += 1;
            }
        }
        return total;
    }
}
時間複雜度分析

上述算法存在雙層嵌套, 因此時間複雜度爲O(N2)O(N^2), 空間複雜度爲O(N2)O(N^2).

中心擴展法(非動態規劃)

對於長度爲N的字符串, 其所有迴文子串可能有2N-1箇中心. 其中長度爲奇數的迴文子串共有N箇中心, 分別是字符串的第1個到第N個字符, 而長度爲偶數的迴文子串其中心爲空.

我們可以分別沿每一中心向外擴展, 計算以當前位置爲中心的迴文子串個數.

class Solution {
    public int countSubstrings(String s) {
        //使用中心擴展法
        //如果迴文子串長度爲奇數, 則其中心分別爲s[0], s[1], ... s[s.length()-1]
        //如果迴文子串長度爲偶數, 則其中心爲空
        int strLen = s.length();

        int total = 0;
        for(int i = 0; i < strLen ; i++){
            //首先判斷長度爲奇數的迴文子串
            int left = i;
            int right = i;
            while(left >= 0 && right < strLen && s.charAt(left) == s.charAt(right)){
                total++;
                left--;
                right++;
            }
            //判斷長度爲偶數的迴文子串
            left = i;
            right = i+1;
            while(left >= 0 && right < strLen && s.charAt(left) == s.charAt(right)){
                total++;
                left--;
                right++;
            }
        }
        return total;
    }
}

該方法的時間複雜度爲O(N2)O(N^2) , 但其空間複雜度爲O(1)O(1)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章