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

LeetCode5最长回文子串

回文串起始位置公式 start = i - (maxLen-1)/2 详解

1. 问题背景

在最长回文子串算法中,我们使用中心扩展法找到回文串后,需要确定其在原字符串中的起始位置。已知:

  • i:扩展中心位置
  • maxLen:找到的最长回文串长度

核心问题:如何根据中心位置和长度,推导出起始位置公式 start = i - (maxLen-1)/2

2. 关键变量含义详解

2.1 变量定义

  • i:当前扩展的中心位置索引
    • 对于奇数长度回文串:i 就是回文串的中心字符位置
    • 对于偶数长度回文串:i 是左侧中心位置(两个中心字符中较左的那个)
  • maxLen:当前找到的最长回文串的长度
  • start:最长回文串在原字符串中的起始位置
  • exp(s, l, r):中心扩展函数,返回以 (l,r) 为中心的最长回文串长度

2.2 扩展函数解析

int exp(String s, int l, int r) {int n = s.length();while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {--l;  // 向左扩展++r;  // 向右扩展}return r - l - 1;  // 返回回文串长度
}

为什么返回 r - l - 1

  • 循环结束时,s[l] ≠ s[r] 或越界
  • 此时 lr 指向回文串外侧
  • 回文串实际范围是 [l+1, r-1]
  • 长度 = (r-1) - (l+1) + 1 = r - l - 1

3. 公式推导过程

3.1 核心思想

回文串具有轴对称特性:

回文串: [左半部分] [中心] [右半部分]←------ 对称轴 ------→

3.2 数学推导

步骤1:分析回文串结构
  • 总长度:maxLen
  • 中心位置:i
  • 问题:从中心位置如何找到起始位置?
步骤2:计算中心左侧字符数

对于长度为 maxLen 的回文串:

  • 奇数长度(如长度5):a b c b a
    • 中心字符:1个
    • 左侧字符数:(5-1)/2 = 2
  • 偶数长度(如长度4):a b b a
    • 中心字符:0个(中心在两字符间)
    • 左侧字符数:(4-1)/2 = 1(整数除法)

统一公式:中心左侧字符数 = (maxLen-1)/2

步骤3:计算起始位置

起始位置 = 中心位置 - 中心左侧字符数

start = i - (maxLen-1)/2

4. 可视化演示

4.1 测试用例设计

我们选择字符串 "babac" 进行完整演示,这个用例能覆盖算法的所有分支:

字符串: "babac"
索引:    0 1 2 3 4
字符:    b a b a c

4.2 完整执行过程

初始状态
maxLen = 0, start = 0
i = 0 时的处理
len1 = exp(s, 0, 0);  // 奇数中心扩展
len2 = exp(s, 0, 1);  // 偶数中心扩展

奇数扩展 exp(0, 0)

初始: l=0, r=0, s[0]='b'
检查: s[0] == s[0] ✓
扩展: l=-1, r=1
检查: l<0 ✗
返回: r-l-1 = 1-(-1)-1 = 1

偶数扩展 exp(0, 1)

初始: l=0, r=1, s[0]='b', s[1]='a'  
检查: s[0] != s[1] ✗
返回: r-l-1 = 1-0-1 = 0

更新状态

len = max(1, 0) = 1
maxLen < len? 0 < 1 ✓
maxLen = 1
start = 0 - (1-1)/2 = 0 - 0 = 0
i = 1 时的处理

奇数扩展 exp(1, 1)

初始: l=1, r=1, s[1]='a'
检查: s[1] == s[1] ✓  
扩展: l=0, r=2
检查: s[0]='b', s[2]='b', s[0] == s[2] ✓
扩展: l=-1, r=3
检查: l<0 ✗
返回: r-l-1 = 3-(-1)-1 = 3

偶数扩展 exp(1, 2)

初始: l=1, r=2, s[1]='a', s[2]='b'
检查: s[1] != s[2] ✗
返回: r-l-1 = 2-1-1 = 0  

更新状态

len = max(3, 0) = 3
maxLen < len? 1 < 3 ✓  
maxLen = 3
start = 1 - (3-1)/2 = 1 - 1 = 0

验证结果

回文串 = s.substring(0, 0+3) = "bab"
i = 2, 3, 4 的处理

继续处理后续位置,但都不会找到更长的回文串,所以最终结果保持不变。

4.3 关键步骤可视化

当 i=1, maxLen=3 时的推导:
原字符串: b a b a c
索引:     0 1 2 3 4↑   ↑   start  i   回文串 "bab":
- 中心位置: i = 1
- 长度: maxLen = 3  
- 中心左侧字符数: (3-1)/2 = 1
- 起始位置: start = 1 - 1 = 0验证:
字符串: b a b a c
索引:   0 1 2 3 4[---]start=0, length=3提取: s.substring(0, 3) = "bab"

5. 算法分支覆盖分析

5.1 代码分支识别

for (int i = 0; i < n; i++) {int len1 = exp(s, i, i);     // 分支1: 奇数长度扩展int len2 = exp(s, i, i + 1); // 分支2: 偶数长度扩展  int len = Math.max(len1, len2);if (maxLen < len) {          // 分支3: 更新最长回文串maxLen = len;start = i - (maxLen-1)/2; // 关键公式}
}

5.2 用例 “babac” 的分支覆盖

i奇数扩展(len1)偶数扩展(len2)max(len1,len2)是否更新覆盖分支
01011,2,3
13031,2,3
21011,2
31011,2
41011,2

结论:用例 “babac” 成功覆盖了所有代码分支。

6. 记忆技巧

6.1 视觉记忆法

回文串想象成一个天平:左边     |中心|     右边↑       ↑        ↑(len-1)/2  支点   (len-1)/2从支点往左数 (len-1)/2 步 = 起始位置
中心位置是i,占据了一个位置,想象代码计算回文串expandAroundCenter(i,i),expandAroundCenter(i,i+1)
(len-1)/2的1是中心占据的位置,所以i-左边长度就是start,因此有
start=i-(maxLen-1)/2

6.2 公式记忆口诀

  1. 回文对称:回文串关于中心轴对称
  2. 左右等分:除去中心,左右各有 (len-1)/2 个字符
  3. 向左偏移:从中心向左偏移 (len-1)/2 就是起始位置

6.3 快速验证法

给定 startmaxLen

  1. 提取字符串:s.substring(start, start + maxLen)
  2. 检查长度:应等于 maxLen
  3. 检查回文:提取的字符串应是回文串

7. 常见错误分析

7.1 错误公式1:start = i - maxLen/2

错误原因:没有考虑中心字符

  • 对于奇数长度,中心字符不应计入左侧
  • 正确应该是 (maxLen-1)/2

7.2 错误公式2:start = i - len1/2start = i - len2/2

错误原因:混淆了扩展长度和最终长度

  • 应该使用 maxLen(最长回文串长度)
  • 而不是单次扩展的长度

7.3 边界错误

问题start 可能为负数
解决:在实际应用中需要检查边界

start = Math.max(0, i - (maxLen-1)/2);

8. 完整算法总结

public String longestPalindrome(String s) {int maxLen = 0;    // 最长回文串长度int n = s.length();int start = 0;     // 最长回文串起始位置for (int i = 0; i < n; i++) {// 尝试奇数长度回文串(以i为中心)int len1 = expandAroundCenter(s, i, i);// 尝试偶数长度回文串(以i,i+1为中心)  int len2 = expandAroundCenter(s, i, i + 1);int len = Math.max(len1, len2);if (len > maxLen) {maxLen = len;// 核心公式:中心位置减去左侧字符数start = i - (maxLen - 1) / 2;}}return s.substring(start, start + maxLen);
}private int expandAroundCenter(String s, int left, int right) {while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {left--;right++;}return right - left - 1;
}

9. 总结

公式 start = i - (maxLen-1)/2 的本质

  1. i 是回文串的中心位置
  2. (maxLen-1)/2 是中心左侧的字符数量
  3. 从中心向左偏移左侧字符数量,就得到起始位置

记忆要点

  • 回文串是轴对称的
  • 知道中心和半径,就能确定起始位置
  • (maxLen-1)/2 就是回文串的"半径"

这个公式适用于所有情况(奇数/偶数长度),是一个优雅而实用的数学推导结果。

http://www.xdnf.cn/news/1479727.html

相关文章:

  • 基于Spark的中文文本情感分析系统研究
  • 空间配置器
  • 【STM32HAL-----NRF24L01】
  • leetcode LCR 159 库存管理III
  • Qt网络通信服务端与客户端学习
  • 第5章递归:分治法
  • Qt文字滚动效果学习
  • MySQL 高可用方案之 MHA 架构搭建与实践
  • 常用配置文件
  • 去中心化投票系统开发教程 第三章:智能合约设计与开发
  • [网络入侵AI检测] docs | 任务二分类与多分类
  • 算法题-链表03
  • react native 出现 FATAL EXCEPTION: OkHttp Dispatcher
  • LeetCode 2841.几乎唯一子数组的最大和
  • AI智能体架构全流程全解析
  • [光学原理与应用-432]:非线性光学 - 既然光也是电磁波,为什么不能直接通过电生成特定频率的光波?
  • 打造一款高稳定、低延迟、跨平台RTSP播放器的技术实践
  • 基于FPGA的电梯控制系统设计(论文+源码)
  • 动态内存分配
  • DeepSeek辅助在64位Linux中编译运行32位的asm-xml-1.4程序
  • Day22_【机器学习—集成学习(1)—基本思想、分类】
  • leetcode 215 数组中的第K个最大元素
  • Jupyter Notebook与cpolar:构建跨地域数据科学协作平台
  • 正态分布 - 计算 Z-Score 的 无偏估计
  • 计算机主板上的那颗纽扣电池的作用是什么?
  • OSG中TerrainManipulator(地形适配操纵器)
  • STM32CubeProgrammer软件安装
  • Qt 中的 Q_OBJECT 宏详解 —— 从源码到底层机制的全面剖析
  • 2023年ASOC SCI2区TOP,改进元启发式算法+考虑医护人员技能水平的家庭健康护理路径规划,深度解析+性能实测
  • 【Redis】缓存的穿透、击穿和雪崩