news 2026/10/14 9:53:20

【动态规划-17】647.回文子串

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【动态规划-17】647.回文子串

题目描述:

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

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

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

示例 1:

输入:s = "abc"输出:3解释:三个回文子串: "a", "b", "c"

示例 2:

输入:s = "aaa"输出:6解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"

解题思路:

方法一:中心扩展法(最优)

核心思路:

回文串一定有一个中心:

  • 奇数长度:中心是一个字符(如"aba"中心是b)

  • 偶数长度:中心是两个字符之间(如"abba"中心是bb之间)

从每个中心向两边扩展,每扩展成功一次,回文子串数量 +1。

具体过程示例:

s = "aaa"

中心 i=0 ('a'): 扩展 → "a" ✅ 中心 i=1 ('a'): 扩展 → "a" ✅, "aaa" ✅ 中心 i=2 ('a'): 扩展 → "a" ✅ 偶数中心: 中心 i=0.5: 扩展 → "aa" ✅ 中心 i=1.5: 扩展 → "aa" ✅ 总共: 3 + 2 + 1 = 6 ✅

代码实现:

class Solution { public: int countSubstrings(string s) { int count = 0; for (int i = 0; i < s.size(); i++) { // 奇数长度回文,中心是 s[i] count += expandAroundCenter(s, i, i); // 偶数长度回文,中心是 s[i] 和 s[i+1] 之间 count += expandAroundCenter(s, i, i + 1); } return count; } private: int expandAroundCenter(string& s, int left, int right) { int count = 0; while (left >= 0 && right < s.size() && s[left] == s[right]) { count++; left--; right++; } return count; } };

复杂度分析:

维度复杂度说明
时间复杂度O(n²)每个中心扩展 O(n),共 n 个中心
空间复杂度O(1)只用常数个变量

方法二:动态规划

核心思路:

状态定义:

dp[i][j]=s[i..j]是否是回文子串。

状态转移:
如果 s[i] == s[j]: 如果 j - i <= 1: dp[i][j] = true(单个或两个字符) 否则: dp[i][j] = dp[i+1][j-1]

代码实现:

class Solution { public: int countSubstrings(string s) { int n = s.size(); vector<vector<bool>> dp(n, vector<bool>(n, false)); int count = 0; // 按长度递增遍历 for (int len = 1; len <= n; len++) { for (int i = 0; i + len - 1 < n; i++) { int j = i + len - 1; if (s[i] == s[j]) { if (len <= 2 || dp[i+1][j-1]) { dp[i][j] = true; count++; } } } } return count; } };

复杂度分析:

维度复杂度说明
时间复杂度O(n²)双重循环
空间复杂度O(n²)dp 数组

方法三:Manacher 算法(O(n))

核心思路:

和 LeetCode 5 题「最长回文子串」的 Manacher 算法一样,但统计的是所有回文子串的数量。

每个中心的回文半径p[i]表示以i为中心的回文半径,这个中心贡献的回文子串数量是(p[i] + 1) / 2。

代码实现:

class Solution { public: int countSubstrings(string s) { // 预处理 string t = "^#"; for (char c : s) { t += c; t += '#'; } t += '$'; int n = t.size(); vector<int> p(n, 0); int center = 0, right = 0; int count = 0; for (int i = 1; i < n - 1; i++) { if (i < right) { p[i] = min(right - i, p[2 * center - i]); } while (t[i + p[i] + 1] == t[i - p[i] - 1]) { p[i]++; } if (i + p[i] > right) { center = i; right = i + p[i]; } count += (p[i] + 1) / 2; } return count; } };

复杂度分析:

维度复杂度说明
时间复杂度O(n)线性
空间复杂度O(n)p 数组

三种方法对比:

方法时间复杂度空间复杂度代码复杂度推荐度
中心扩展O(n²)O(1)简单⭐⭐⭐⭐⭐
动态规划O(n²)O(n²)中等⭐⭐⭐⭐
ManacherO(n)O(n)复杂⭐⭐⭐

中心扩展是面试首选:代码简洁,空间 O(1)。

关键细节:

1. 为什么中心扩展要处理奇偶两种情况?

  • 奇数回文:"aba",中心是单个字符

  • 偶数回文:"abba",中心是两个字符之间

所以需要对每个位置调用两次扩展:expand(i, i)和expand(i, i+1)。

2. 为什么每扩展成功一次就count++?

因为每扩展成功一次,就发现了一个新的回文子串。

3. 动态规划的遍历顺序

必须按长度递增遍历,因为dp[i][j]依赖dp[i+1][j-1](更短的子串)。

4. 和「最长回文子串」的区别

题目区别
5. 最长回文子串求最长的那一个
647. 回文子串统计所有回文子串的个数

总结:

要点说明
核心思想从每个中心向两边扩展,统计回文个数
关键操作奇数中心(i,i),偶数中心(i,i+1)
时间复杂度O(n²)
空间复杂度O(1)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 9:52:54

187张真实管道漏水图像数据集:YOLO/VOC双格式小目标检测

简介&#xff1a;本资源是一份面向计算机视觉初学者与目标检测实践者的专业级管道漏水检测数据集&#xff0c;适用于工业巡检、智能运维及AI安全监测等实际场景的模型训练与算法验证。数据集共187张清晰分辨率JPG图像&#xff0c;全部完成人工标注&#xff0c;涵盖家庭管道、下…

作者头像 李华
网站建设 2026/10/14 9:52:46

PS5实用方案合集:从初始化到维护的完整操作指南

第一次看到“AnyPS5”这个标题的时候&#xff0c;我第一反应是&#xff1a;这又是一个什么黑科技工具&#xff1f;是把PS5改装成电脑&#xff0c;还是搞什么模拟器全家桶&#xff1f;后来自己折腾了一圈才明白&#xff0c;它其实代表的是一整套围绕PS5主机的“实用方案合集”—…

作者头像 李华
网站建设 2026/10/14 9:52:46

智能体技能库设计与实践:从工具函数到可持续生长的Agent技能管理

做 Agent 的人&#xff0c;迟早会撞上“技能管理”这堵墙。项目跑通是一回事&#xff0c;让它稳定地复用、扩展、不失控&#xff0c;是另一回事。我最近整理项目时&#xff0c;发现不少精力其实都花在“agent-skills”这个环节上——也就是给智能体搭一套可持续生长的技能库。今…

作者头像 李华
网站建设 2026/10/14 9:52:20

PyQt5与OpenCV实现实时摄像头应用开发指南

1. 项目概述 这个项目实现了一个基于PyQt5和OpenCV的实时摄像头应用&#xff0c;能够通过电脑摄像头捕获视频流&#xff0c;并进行实时处理和显示。作为一名长期从事计算机视觉开发的工程师&#xff0c;我发现这种基础框架在实际工作中有着广泛的应用场景 - 从简单的视频监控到…

作者头像 李华
网站建设 2026/10/14 9:52:13

SAR/ISAR成像RD与BP算法MATLAB工程拆解与避坑指南

简介&#xff1a;面向SAR/ISAR成像学习者的MATLAB程序包&#xff0c;完整实现了BP&#xff08;后向投影&#xff09;与RD&#xff08;距离多普勒&#xff09;两种经典成像算法&#xff0c;适用于课程设计、科研入门与算法复现。通过脚本可对比最近邻、双线性、三次样条等不同插…

作者头像 李华
网站建设 2026/10/14 9:51:56

Python音频智能分割:Whisper与PyDub实战

1. 项目背景与核心价值 音频处理是很多内容创作者、播客制作者和语音转文字工作者的日常需求。在实际工作中&#xff0c;我们经常遇到需要将长时间录音分割成小段的场景——可能是为了提取关键对话片段&#xff0c;也可能是为了适配不同平台的上传限制。传统音频编辑软件虽然能…

作者头像 李华