LC5 最长回文子串
1 枚举(超时)
stringPalindrome(string s) {
int len = s.length();
if(len < 2) return s;
int maxlen = 1;
int begin = 0;
for(int i = 0; i < len - 1; ++i) {
for(int j = i + 1; j < len; ++j) {
if(j - i + 1 > maxlen && isValidPalindrome(s, i, j)) {
maxlen = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxlen);
}
bool isValidPalindrome(string s, int left, int right) {
while(left < right) {
if(s[left] != s[right]) return false;
left++;
right++;
}
return true;
}
2 动态规划
状态定义:dp[i][j] :s[i,j] 是否为回文子串
string longestPalindrome(string s) {
int n = s.length();
if(n < 2) return s;
int maxlen = 1;
int begin = 0;
vector<vector<int>> dp(n, vector<int>(n));
for(int i = 0; i < n; ++i) {
dp[i][i] = true;
}
for(int len = 2; len <= n; ++len) {
for(int i = 0; i < n; ++i) {
int j = i + len - 1;
if(j >= n) break;
if(s[i] != s[j]) {
dp[i][j] = false;
}
else {
if(len <= 3) {
dp[i][j] = true;
}
else {
dp[i][j] = dp[i + 1][j - 1];
}
}
if(dp[i][j] && j - i + 1 > maxlen) {
maxlen = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxlen);
}
3 中心扩展法
string longestPalindrome(string s) {
int n = s.length();
int left = 0, right = 0;
for(int i = 0; i < n; ++i) {
int oddlen = expandCenter(s, i, i);
int evenlen = expandCenter(s, i, i + 1);
int maxlen = max(oddlen, evenlen);
if(maxlen > right - left + 1) {
left = i - (maxlen - 1) / 2;
right = i + maxlen / 2;
}
}
return s.substr(left, right - left + 1);
}
int expandCenter(string s, int left, int right) {
while(left >= 0 && right < s.length() && s[left] == s[right]) {
left--;
right++;
}
return right - left - 1;
}
LC647 回文子串
给定字符串,计算这个字符串有多少个回文子串?
1 枚举
int countSubstrings(string s) {
int n = s.length();
int cnt = n;
for(int i = 0; i < n; ++i) {
for(int j = i + 1; j < n; ++j) {
if(isValidSubstring(s, i, j)) {
cnt += 1;
}
}
}
return cnt;
}
bool isValidSubstring(string s, int left, int right) {
while(left < right) {
if(s[left] != s[right]) return false;
left++;
right--;
}
return true;
}
2 动态规划
在上一道题的基础上修改:
int countSubstrings(string s) {
int n = s.length();
if(n < 2) return n;
int cnt = n;
vector<vector<bool>> dp(n, vector<bool>(n));
for(int i = 0; i < n; ++i) {
dp[i][i] = true;
}
for(int len = 2; len <= n; ++len) {
for(int i = 0; i < n ; ++i) {
int j = i + len - 1;
if(j >= n) break;
if(s[i] != s[j]) dp[i][j] = false;
else {
if(len <= 3) {
dp[i][j] = true;
}
else {
dp[i][j] = dp[i + 1][j - 1];
}
}
if(dp[i][j]) cnt += 1;
}
}
return cnt;
}
参考评论区的一种解法:
dp[j] 表示从j位置到当前遍历到的字符位置i是否为回文字符串
int countSubstrings(string s) {
int n = s.length();
vector<int> dp(n);
int res = 0;
for(int i = 0; i < n; ++i) {
dp[i] = 1;
res++;
for(int j = 0; j < i; ++j) {
if(s[j] == s[i] && dp[j + 1] == 1) {
dp[j] = 1;
res++;
}
else {
dp[j] = 0;
}
}
}
return res;
}
3 中心扩展法
int res = 0;
int countSubstrings(string s) {
int n = s.length();
if(n < 2) return n;
for(int i = 0; i < n; ++i) {
expandCenter(s, i, i);
expandCenter(s, i, i + 1);
}
return res;
}
void expandCenter(string& s, int left, int right) {
while(left >= 0 && right < s.size() && s[left] == s[right]) {
res++;
left--;
right++;
}
}
|