回文子串个数
1. 確定dp數組(dp table)以及下標的含義
布爾類型的dp[i][j]:表示區間范圍[i,j](注意是左閉右閉)的子串是否是回文子串,如果是dp[i][j]為true,否則為false。
2. 確定遞推公式
在確定遞推公式時,整體上有兩種情況,就是s[i]與s[j]相等,s[i]與s[j]不相等這兩種。
當s[i]與s[j]不相等,dp[i][j]一定是false。
當s[i]與s[j]相等時,又分為如下三種情況
- 情況一:下標i 與 j相同,同一個字符例如a,當然是回文子串
- 情況二:下標i 與 j相差為1,例如aa,也是文子串
- 情況三:下標:i 與 j相差大于1的時候,例如cabac,此時s[i]與s[j]已經相同了,我們看i到j區間是不是回文子串就看aba是不是回文就可以了,那么aba的區間就是 i+1 與 j-1區間,這個區間是不是回文就看dp[i + 1][j - 1]是否為true。
3. dp數組如何初始化
dp[i][j]可以初始化為true么? 當然不行,怎能剛開始就全都匹配上了。
所以dp[i][j]初始化為false。
4. 確定遍歷順序
首先從遞推公式中可以看出,情況三是根據dp[i + 1][j - 1]是否為true,在對dp[i][j]進行賦值true的。
dp[i + 1][j - 1] 在 dp[i][j]的左下角,如圖:
如果這矩陣是從上到下,從左到右遍歷,那么會用到沒有計算過的dp[i + 1][j - 1],也就是根據不確定是不是回文的區間[i+1,j-1],來判斷了[i,j]是不是回文,那結果一定是不對的。
所以一定要從下到上,從左到右遍歷,這樣保證dp[i + 1][j - 1]都是經過計算的。
5. 舉例推導dp數組
舉例,輸入:“aaa”,dp[i][j]狀態如下:
圖中有6個true,所以就是有6個回文子串。
注意因為dp[i][j]的定義,所以j一定是大于等于i的,那么在填充dp[i][j]的時候一定是只填充右上半部分。
以上分析完畢,C++代碼如下:
class Solution { public:int countSubstrings(string s) {vector<vector<bool>> dp(s.size(),vector<bool>(s.size(),false));int res=0;for(int ii=s.size()-1;ii>=0;ii--){//從下到上遍歷for(int jj=ii;jj<s.size();jj++){//從左到右遍歷if(s[ii]!=s[jj]) dp[ii][jj]=false;else if(s[ii]==s[jj]){if(jj-ii<=2){dp[ii][jj]=true;res++;} else if(dp[ii+1][jj-1]){res++;dp[ii][jj]=true;}}}}return res;} };簡潔版
class Solution { public:int countSubstrings(string s) {vector<vector<bool>> dp(s.size(), vector<bool>(s.size(), false));int result = 0;for (int i = s.size() - 1; i >= 0; i--) {for (int j = i; j < s.size(); j++) {if (s[i] == s[j] && (j - i <= 1 || dp[i + 1][j - 1])) {result++;dp[i][j] = true;}}}return result;} }; 時間復雜度:O(n^2) 空間復雜度:O(n^2)雙指針法
動態規劃的空間復雜度是偏高的,我們再看一下雙指針法。
首先確定回文串,就是找中心然后想兩邊擴散看是不是對稱的就可以了。
在遍歷中心點的時候,要注意中心點有兩種情況。
一個元素可以作為中心點,兩個元素也可以作為中心點。
那么有人同學問了,三個元素還可以做中心點呢。其實三個元素就可以由一個元素左右添加元素得到,四個元素則可以由兩個元素左右添加元素得到。
所以我們在計算的時候,要注意一個元素為中心點和兩個元素為中心點的情況。
class Solution { public:int countSubstrings(string s) {int result = 0;for (int i = 0; i < s.size(); i++) {result += extend(s, i, i, s.size()); // 以i為中心result += extend(s, i, i + 1, s.size()); // 以i和i+1為中心}return result;}int extend(const string& s, int i, int j, int n) {int res = 0;while (i >= 0 && j < n && s[i] == s[j]) {i--;j++;res++;}return res;} }; 時間復雜度:O(n^2) 空間復雜度:O(1)總結
- 上一篇: 绝杀编辑距离
- 下一篇: 一块钱买一瓶水,两个空瓶换一瓶水,三个瓶