当前位置: 首页 > news >正文

LeetCode算法日记 - Day 95: 回文子串

目录

1. 回文子串

1.1 题目解析

1.2 解法

1.3 代码实现


1. 回文子串

https://leetcode.cn/problems/palindromic-substrings/description/

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

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

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= s.length <= 1000
  • s 由小写英文字母组成

1.1 题目解析

题目本质
这是一个子串统计问题,要统计一个字符串中所有回文子串的数量。本质上是判断每个可能的子串是否为回文,然后累加计数。核心是"如何高效判断所有子串的回文性质"。

常规解法
最直观的想法:枚举所有可能的子串,对每个子串都进行回文判断。

// 常规解法:暴力枚举(可能超时)static class BruteForceSolution {public int countSubstrings(String s) {int n = s.length();int count = 0;// 枚举所有可能的子串for (int i = 0; i < n; i++) {for (int j = i; j < n; j++) {// 判断 s[i..j] 是否为回文if (isPalindrome(s, i, j)) {count++;}}}return count;}// 判断 s[left..right] 是否为回文private boolean isPalindrome(String s, int left, int right) {while (left < right) {if (s.charAt(left) != s.charAt(right)) {return false;}left++;right--;}return true;}}

问题分析
暴力枚举的复杂度是 O(n³):当 n = 1000 时,1000³ = 10⁹ 次操作,可能会超时。
关键观察:回文判断存在大量重复计算

  • 判断 "abcba" 是否为回文时,会检查 "bcb"

  • 之后判断 "bcb" 是否为回文时,又要重新检查一遍

  • 这种重复计算可以被优化!

思路转折
要想高效 → 必须避免重复判断 → 动态规划预处理
核心洞察:大回文串依赖于小回文串

  • 如果 "aba" 是回文,那么只需要看首尾字符是否相等

  • 如果 s[i] == s[j],且 s[i+1..j-1] 是回文,那么 s[i..j] 也是回文

1.2 解法

算法思想
1. 采用区间动态规划:定义 dp[i][j] = s[i..j] 是否为回文子串

2. 状态转移:

  • 单字符:dp[i][i] = true
  • 相邻字符:dp[i][i+1] = (s[i] == s[i+1])
  • 其他情况:dp[i][j] = (s[i] == s[j]) && dp[i+1][j-1]

3. 遍历顺序:i 从大到小(n-1 → 0),j 从小到大(i → n-1)

4. 统计所有 dp[i][j] == true 的数量

步骤拆解

i)初始化:创建 boolean[][] dp,默认全为 false

ii)填表:

  • 外层循环:i 从 n-1 倒序到 0

  • 内层循环:j 从 i 正序到 n-1

  • 判断 s[i] 是否等于 s[j]:

    • 相等 + 单字符 → dp[i][j] = true

    • 相等 + 相邻 → dp[i][j] = true

    • 相等 + 其他 → dp[i][j] = dp[i+1][j-1]

    • 不相等 → 保持 false

iii)统计:遍历 dp 数组,累加所有 true 的个数

易错点

  • 遍历顺序错误:必须 i 倒序(从大到小),因为 dp[i][j] 依赖 dp[i+1][j-1],需要先计算大的 i。如果 i 正序,会访问到未计算的状态

  • 统计时遍历范围错误:不能遍历整个 n×n 矩阵,因为 j < i 的部分没有意义。应该只遍历上三角(j ≥ i),或者统计时也用双重循环 for(i) for(j=i to n-1)

  • 边界条件遗漏:忘记处理单字符(i==j)和相邻字符(i+1==j)的情况,直接访问 dp[i+1][j-1] 会越界或逻辑错误

  • 首尾不等时未处理:当 s[i] != s[j] 时,应该保持 dp[i][j] = false,不需要显式赋值(Java默认false)

1.3 代码实现

// 回文子串的数目
static class Solution {public int countSubstrings(String s) {int n = s.length();char[] nums = s.toCharArray();boolean[][] dp = new boolean[n][n];// 填表:i 倒序,j 正序for (int i = n-1; i >= 0; i--) {for (int j = i; j < n; j++) {if (nums[i] == nums[j]) {// 首尾字符相等if (i == j) {dp[i][j] = true;  // 单字符} else if (i+1 == j) {dp[i][j] = true;  // 相邻字符} else {dp[i][j] = dp[i+1][j-1];  // 看内部}}// 首尾不等,保持 false}}// 统计回文子串数量int ret = 0;for (int i = 0; i < n; i++) {for (int j = i; j < n; j++) {  // 只遍历上三角if (dp[i][j]) ret++;}}return ret;}
}

复杂度分析

  • 时间复杂度:O(n²)

  • 空间复杂度:O(n²)

http://www.dtcms.com/a/580973.html

相关文章:

  • DockerCompose与多容器编排
  • AngularJS与SQL的集成使用指南
  • 【ZeroRange WebRTC】TWCC 在 WebRTC 中的角色与工作原理(深入指南)
  • 数据结构常见的八大排序算法
  • 个人怎么做网站app推广引流方法
  • 初识光伏逆变器
  • 一文了解LLM应用架构:从Prompt到Multi-Agent
  • MongoDB 内存管理避坑指南:解决高占用、页错误等核心问题,让数据库性能翻倍
  • 关于DNS中毒攻击的解决方案分享
  • 【C++】数据挖掘算法在软件测试中的应用
  • WebSocket 完全指南:从原理到实战,搭建实时通信桥梁
  • STM32项目分享:智能水产养殖系统
  • 网站开发线框个体营业执照网上年报
  • iPhone苹果手机拍的照片默认是heic如何换成jpg格式
  • 基于微信小程序的旅游攻略分享互动平台设计与实现-项目分享
  • Neo4j Windows桌面版安装及更改默认数据存储位置
  • 智能安防新篇章:EasyGBS助力重塑物业视频管理服务
  • ps2017做网站当阳网站建设电话
  • H5短视频SDK,赋能Web端视频创作革命
  • 如何选择温州本凡科技进行小程序开发服务?
  • 融智兴科技邀您共赴2025中国洗涤展
  • STM32上使用HAL库完美实现驱动MAX98357声卡模块(I2S+DMA+音频环形缓冲区)
  • 【React】打卡笔记,入门学习03:useState、useEffect、useRef、useMemo
  • M|烟花 (1995)
  • 平顶山网站建设2022年黄台片区
  • 人工智能的未来之路:华为全栈技术链与AI Agent应用实践
  • 基于openresty反向代理、dns劫持、实现对http请求、响应内容抓包
  • 智能体的范式革命:华为全栈技术链驱动下一代AI Agent
  • AI 边缘计算:决胜未来
  • 【Linux】网络层协议