題目來源:力扣
題目介紹:
給定一個字符串,你的任務是計算這個字符串中有多少個迴文子串。
具有不同開始位置或結束位置的子串,即使是由相同的字符組成,也會被計爲是不同的子串。
=============================================================
示例 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;
}
}
時間複雜度分析
上述算法存在雙層嵌套, 因此時間複雜度爲, 空間複雜度爲.
中心擴展法(非動態規劃)
對於長度爲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;
}
}
該方法的時間複雜度爲 , 但其空間複雜度爲