647. 迴文子串
題目連結:https://leetcode.cn/problems/palindromic-substrings/
文章講解:https://programmercarl.com/0647.迴文子串.html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV17G4y1y7z9/
題目狀態:看題解
思路一:動態規劃
使用一個二維動規陣列dp[i][j]
來儲存從s[i]
到s[j]
(或從s[j]
到s[i]
,一樣的,本題程式碼是從j到i)是否屬於迴文子串。兩層遍歷該字串,來記錄迴文子串的個數。
- 當
s[i] == s[j]
時,要判斷一下i
和j
的距離,若i和j的距離為0和1,則表示這是一個迴文子串。 - 當
s[i] == s[j]
時,但i
和j
的距離較大,那麼就要看其裡面的一個是不是迴文子串。
程式碼一:
class Solution {
public:
int countSubstrings(string s) {
int len = s.size();
vector<vector<bool>> dp(len, vector<bool>(len, false));
int ans = 0;
for(int i = len - 1; i >= 0; --i) {
for(int j = i; j < len; ++j) {
if(s[i] == s[j]) {
if(j - i <= 1) {
ans++;
dp[i][j] = true;
} else if(dp[i + 1][j - 1]){
ans++;
dp[i][j] = true;
}
}
}
}
return ans;
}
};
思路二:雙指標
使用一個輔助函式extend
來遍歷有多少子串,其中i和j分別是兩個起點指標,兩個指標分別向前和向後遍歷,如果遇到i不等於j的時候,就可以返回了,結果就是以i和j為中間點的子串有多少。而在主函式中,兩次呼叫extend
函式分別表示奇子串和偶子串。
程式碼二:
class Solution {
public:
int countSubstrings(string s) {
int ans = 0;
for(int i = 0; i < s.size(); ++i) {
ans += extend(s, i, i, s.size());
ans += extend(s, i, i + 1, s.size());
}
return ans;
}
int extend(const string &s, int i, int j, int n) {
int ans = 0;
while(i >= 0 && j < n && s[i] == s[j]) {
i--;
j++;
ans++;
}
return ans;
}
};
516. 最長迴文子序列
題目連結:https://leetcode.cn/problems/longest-palindromic-subsequence/
文章講解:https://programmercarl.com/0516.最長迴文子序列.html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV1d8411K7W6/
題目狀態:看題解
思路:
維護一個動規陣列dp[i][j]
表示從s[i]
到s[j]
的最長迴文子序列的大小。
- 當
s[i] == s[j]
時,表示其是一個迴文序列,因此將這兩個字元加入進來,即dp[i][j] = dp[i + 1][j - 1] + 2
。 - 當
s[i] != s[j]
時,我們就需要找在這個範圍裡的最大子序列的個數了。
程式碼:
class Solution {
public:
int longestPalindromeSubseq(string s) {
int len = s.size();
vector<vector<int>> dp(len, vector<int>(len, 0));
for(int i = 0; i < len; ++i) dp[i][i] = 1;
for(int i = len - 1; i >= 0; --i) {
for(int j = i + 1; j < len; ++j) {
if(s[i] == s[j]) dp[i][j] = dp[i + 1][j - 1] + 2;
else dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
return dp[0][len - 1];
}
};