0%

647. 回文子串

647.回文子串

题目描述:

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

回文字符串 是正着读和倒过来读一样的字符串。

子字符串 是字符串中的由连续字符组成的一个序列。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

数据范围:

$1 \le s.length \le 1000$

题解:

使用马拉车或者中心扩展算法。

中心扩展算法,每次枚举扩展中心 $[i, i]$ 或 $[i, i + 1]$ ,然后每次从扩展中心向两边扩展,一个减减一个加加。遇到不相等的字符直接返回长度即可。

动态规划:

可以用一个回文串的信息,去扩展比他更长的回文串。

如果 $aaa$ 是回文串,那么 $xaaax$ 也是回文串。所以需要使用 $dp[i][j]$ 表示区间 $[i, j]$ 是不是回文串。

对于一个新区间 $[i, j]$ 来说,如果 $s[i] = s[j]$ ,并且 $[i + 1, j - 1]$ 是回文串,那么 $[i, j]$ 也是回文串。可以直接使用区间dp,先预处理出长度为 $i \ge j$ 的区间全是回文串,然后对于 $len \in [2, n]$ 的区间, 判断 $[i + 1, j - 1]$ 是不是回文串即可。

代码:

中心扩展算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
auto optimize_cpp_stdio = []()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
class Solution
{
public:
const static int maxn = 1e5 + 10;
const static int maxm = 1e5 + 10;
const static long long mod = 1e9 + 7;
const long long INF_LL = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
int extend(int left, int right, string &s)
{
int cnt = 0;
int n = s.length();
for (; left >= 0 && right < n; --left, ++right)
{
if (s[left] != s[right])
break;
++cnt;
}
return cnt;
}
int countSubstrings(string s)
{
int n = s.length();
int count = 0;
for (int i = 0; i < n; ++i)
{
count += extend(i, i, s) + extend(i, i + 1, s);
}
return count;
}
};

动态规划算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
auto optimize_cpp_stdio = []()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
class Solution
{
public:
const static int maxn = 1e5 + 10;
const static int maxm = 1e5 + 10;
const static long long mod = 1e9 + 7;
const long long INF_LL = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
int countSubstrings(string s)
{
int n = s.length();
vector<vector<bool>> dp(n, vector<bool>(n));
for (int i = 0; i < n; ++i)
{
dp[i][i] = 1;
}
int count = n;
for (int len = 2; len <= n; ++len)
{
for (int i = 0; i + len - 1 < n; ++i)
{
int j = i + len - 1;
if (s[i] == s[j])
{
if (len <= 3 || dp[i + 1][j - 1])
{
dp[i][j] = true;
count++;
}
}
}
}
return count;
}
};