647. 回文子串 - 力扣(LeetCode)
思路:
-
动态规划思路
-
-
确定dp数组以及下标的含义
dp[i][j]
的定义为:字符串[i:j]是否为回文串
-
确定递推公式
// 状态转移方程 // 如果不相等,肯定是false,不用管 // 如果相等,要判断j - i的差值,如果大于1则要继续判断dp[i + 1][j - 1]是否为true 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; } }
-
dp数组如何初始化
// 因为要判断是否为回文串,所以开局全部置为false
-
确定遍历顺序
// 因为需要dp[i + 1][j - 1]的数据,所以需要从下往上,从左往后遍历 // 由于dp[i][j]的定义是字符串[i:j]是否为回文串,所以遍历时必须满足j >= i,即内循环开始时j = i for(int i = s.size() - 1; i >= 0; --i) { for(int j = i; j < s.size(); ++j) { } }
-
-
双指针法思路
- 遍历字符串,分别以一个字符和两个字符为中心扩散查找是否为回文串
我的AC代码
动态规划
// 时间复杂度O(n^2),空间复杂度O(n^2)
class Solution {
public:
int countSubstrings(string s) {
vector<vector<bool>> dp(s.size(), vector(s.size(), false));
int ans = 0;
for(int i = s.size() - 1; i >= 0; --i) {
for(int j = i; j < s.size(); ++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;
}
};
双指针法
// 时间复杂度O(n^2),空间复杂度O(1)
class Solution {
public:
int countSubstrings(string s) {
int ans = 0;
for(int i = 0; i < s.size(); ++i) {
ans += extend(s, i, i);
ans += extend(s, i, i + 1);
}
return ans;
}
int extend(string& s, int i, int j) {
int ans = 0;
while(i >= 0 && j < s.size() && s[i] == s[j]) {
i--;
j++;
ans++;
}
return ans;
}
};
标准答案
动态规划
// 时间复杂度O(n^2),空间复杂度O(n^2)
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(1)
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;
}
};
516. 最长回文子序列 - 力扣(LeetCode)
思路:
-
使用动态规划
-
-
确定dp数组以及下标的含义
dp[i][j]
的定义为:字符串[i:j]的最长回文子序列
-
确定递推公式
// 状态转移方程 // s[i]和s[j]不相等的时候,从dp[i + 1][j], dp[i][j - 1]找大的 // 相等的时候,分两种情况,一种j == i,那么都是1 // 还有一种j != i,那么最长回文序列数量则为dp[i + 1][j - 1] + 2 if(s[i] != s[j]) { dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); } else { if(j == i) { dp[i][j] = 1; } else { dp[i][j] = dp[i + 1][j - 1] + 2; } }
-
dp数组如何初始化
// vector<vector<int>> dp(s.size(), vector<int> (s.size(), 0));
-
确定遍历顺序
// 从左到右,从下到上
-
我的AC代码
// 时间复杂度O(n^2),空间复杂度O(n^2)
class Solution {
public:
int longestPalindromeSubseq(string s) {
vector<vector<int>> dp(s.size(), vector<int> (s.size(), 0));
for(int i = s.size() - 1; i >= 0; --i) {
for(int j = i;j < s.size(); ++j) {
if(s[i] != s[j]) {
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
else {
if(j == i) {
dp[i][j] = 1;
}
else {
dp[i][j] = dp[i + 1][j - 1] + 2;
}
}
}
}
return dp[0][s.size() - 1];
}
};
标准答案
// 时间复杂度O(n^2),空间复杂度O(n^2)
class Solution {
public:
int longestPalindromeSubseq(string s) {
vector<vector<int>> dp(s.size(), vector<int>(s.size(), 0));
for (int i = 0; i < s.size(); i++) dp[i][i] = 1;
for (int i = s.size() - 1; i >= 0; i--) {
for (int j = i + 1; j < s.size(); 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][s.size() - 1];
}
};
Comments NOTHING