回文子串
原题在这里:
概述题意,问给定字符串s中有多少个子串是回文串,不同下标构成的子串视为不同子串。
analyse:
1.暴力,数据范围只有1e3,substr+reverse暴力判断
code:

class Solution { bool check(string s) { string x = s; reverse(x.begin(), x.end()); return x == s; } public: int countSubstrings(string s) { /* analyse: 尝试翻译为KMP: 末位跳转次数+len? len<=1000 x 肯定是有数据结构的规律的,但是这里就写暴力了 */ int ans = 0; for (int i = 0; i < s.length(); ++i) for (int j = s.length() - i; j > 0; --j) ans += check(s.substr(i, j)); return ans; } };
2.中心拓展,但不是想当然式的两边+1+1那种,考虑中心的奇偶性,分为两种判断:
code:

class Solution { int ans = 0; int count(string s, int l, int r) { int num = 0; while (l >= 0 && r < s.length() && s[l] == s[r]) ++num, --l, ++r; return num; } public: int countSubstrings(string s) { for (int i = 0; i < s.length(); ++i) ans += count(s, i, i) + count(s, i, i + 1); return ans; } };
3.manacher,也属于是中心拓展,但是manacher会利用前面判断对后序判断进行优化,等于是中心拓展的优化。
关键点在于:对于manacher的中心数组p的使用,p[i]表示以i为中心的最长回文串半径,那么对于有多少个回文子串即为sum(p[i]/2)即可,因为p所处理的字符串为预处理过的字符串,所以单个字符构成的字符串并不计入在内。
code:
class Solution { string S; void Init(string s) { S = "~#"; for (char i : s) S += i, S += '#'; } int manacher(string s) { int mx = 0, id = 0, l = s.length(); int ans = 0; // mx最大右端点,id最长回文串中心点 vector<int> p(l); for (int i = 1; i < l; ++i) { if (mx > i) p[i] = min(mx - i, p[id - (i - id)]); else p[i] = 1; while (s[i - p[i]] == s[i + p[i]]) ++p[i]; if (p[i] + i > mx) { mx = p[i] + i; id = i; } ans += p[i] / 2; } return ans; } public: int countSubstrings(string s) { /* analyse: 翻译为manacher: p[i]表示以i为中心的最长回文串半径长度,那么最终ans=sum(p[i]/2) */ Init(s); return manacher(S); } };
【Over】
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!