题目描述:
给你一个字符串 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; } };
|