Python实现Manacher算法:从暴力枚举到线性时间复杂度

星野
星野
发布时间:2026-10-13| 3人浏览过
原创

本文深入解析Python中求最长回文子串的算法演进。从时间复杂度为O(N^2)的暴力枚举出发,介绍中心扩展法的优化思路,最终重点讲解Manacher算法。该算法利用回文对称性将时间复杂度优化至O(N),并通过1000字符纯'a'字符串的实测数据,展示Manacher算法在耗时上相比暴力法(49.7s)和中心扩展法(0.33s)的显著优势,耗时仅0.008s。

给定一个字符串,任务是在其中寻找符合回文定义的最长子串。回文串是指正读和反读都相同的字符串,例如“aba”、“ababa”或“abba”。需要注意的是,单个字符以及两个相邻的相同字符也满足回文性质。

面对这一问题,最直观的解法是暴力枚举。该方法通过遍历字符串所有可能的子串起点,逐一检查子串是否满足回文条件,并记录最大长度。然而,这种算法的时间复杂度极高,最坏情况下达到O(N^2)。因此,一种优化方案是枚举子串的中心而非起点,从中心向两侧同时扩展以判断回文性。这种优化在字符串字符高度重复(如全为同一字符)的最坏场景下,能显著提升运行效率。

基于上述中心枚举的思路,虽然效率优于暴力法,但仍非最优。由于中心枚举同时涉及中心两侧的字符,我们可以利用对称性:若已知以左侧某点j为中心的最长回文子串长度,可据此推断以右侧对应点i为中心的回文性质。这一核心思想构成了Manacher算法的基础。

Manacher算法的设计十分精妙。假设当前遍历到的位置为i,若存在之前的位置j(j<i)已计算出其最长回文子串长度f[j],则该位置的影响范围覆盖为[j-f[j]/2, j+f[j]/2]。为了使左侧字符j对右侧当前点i的影响最大化,我们需要找到使右边界j+f[j]/2最大的那个j。一旦确定该j,若当前点i位于区间[j, j+f[j]/2]内,则需分两种情况讨论:

第一种情况是:i关于j的对称点i'的影响范围完全包含在j的影响范围内。根据回文串的对称性质,i的影响范围至少等于i'的影响范围,即f[i] >= f[i']。

第二种情况是:i关于j的对称点i'的影响范围未完全包含在j的影响范围内。此时,i右侧的有效影响范围至少延伸至[j-f[j]/2, i'],即满足不等式i+f[i]/2 >= i'-j+f[j]/2。

利用对称性关系i+i' = 2*j,可以推导出:在第一种情况下,f[i] >= f[2*j-i];在第二种情况下,f[i] >= f[j]+2*j-2*i。

综合上述两种情况,可得f[i] >= min(f[2*j-i], f[j]+2*j-2*i)。由于i右侧可能存在尚未遍历的字符,因此在此下限基础上,算法继续向两侧扩展,直到确定最长的回文子串。特别注意,当i右侧存在未处理字符时,初始值至少为1,需在此基础上继续扩展。

若当前点i位于j+f[j]/2之后,说明i未受到之前已计算字符的影响,此时只能从i开始逐一向两侧扩展判断。

该算法的优势在于只需遍历字符串一次,且扩展次数有限,因此整体时间复杂度可优化至O(N)。

以下是Python 3的实现代码。为了验证算法效率,代码中同时保留了最初的暴力枚举算法作为参照,用于对比最坏情况下的性能差异。

Python代码实现如下:

#求最长回文串类 
class LPS:      
 #初始化,需要提供一个字符串 
 def __init__(self,string): 
  self.string = string 
  self.lens = len(self.string) 
  
 #暴力枚举:作为算法效率参照 
 def brute_force(self): 
  maxcount = 0 
  for j in range(self.lens):      
   for k in range(j,self.lens): 
    count = 0 
    l,m = j,k 
    while m>=l: 
     if self.string[l]==self.string[m]: 
      l,m = l+1,m-1 
     else: 
      break 
    if m<l: 
     count = k-j+1 
    if count>maxcount : 
     maxcount = count 
  return maxcount 
  
 #优化版:枚举子串中心 
 def brute_force_opti(self): 
  maxcount = 0 
  if self.lens == 1:        #只有一个字符直接返回1 
   return 1 
  for j in range(self.lens-1):     #枚举中心 
   count,u = 1,j 
   #对于奇数子串,直接扩展 
   for k in range(1,j+1):      #两边扩展 
    l,m = u+k,j-k 
    if (m>=0)&(l<self.lens): 
     if(self.string[l]==self.string[m]): 
      count += 2 
     else: 
      break 
   if count>maxcount :       #更新回文子串最长长度 
    maxcount = count 
   if self.string[j]==self.string[j+1]:  #处理偶数子串,将两个相邻相同元素作为整体 
    u,count= j+1,2 
   for k in range(1,j+1):      #两边扩展 
    l,m = u+k,j-k 
    if (m>=0)&(l<self.lens): 
     if(self.string[l]==self.string[m]): 
      count += 2 
     else: 
      break 
   if count>maxcount :       #更新回文子串最长长度 
    maxcount = count 
  return maxcount 
   
 #manacher算法 
 def manacher(self): 
  s = '#'+'#'.join(self.string)+'#'    #字符串处理,用特殊字符隔离字符串,方便处理偶数子串 
  lens = len(s) 
  f = []           #辅助列表:f[i]表示i作中心的最长回文子串的长度 
  maxj = 0          #记录对i右边影响最大的字符位置j 
  maxl = 0          #记录j影响范围的右边界 
  maxd = 0          #记录最长的回文子串长度 
  for i in range(lens):       #遍历字符串 
   if maxl>i:         
    count = min(maxl-i,int(f[2*maxj-i]/2)+1)#这里为了方便后续计算使用count,其表示当前字符到其影响范围的右边界的距离 
   else :          
    count = 1 
   while i-count>=0 and i+count<lens and s[i-count]==s[i+count]:#两边扩展 
    count +=1 
   if(i-1+count)>maxl:       #更新影响范围最大的字符j及其右边界 
     maxl,maxj = i-1+count,i               
   f.append(count*2-1) 
   maxd = max(maxd,f[i])      #更新回文子串最长长度 
  return int((maxd+1)/2)-1      #去除特殊字符 

使用长度为1000的纯'a'字符串作为测试样例,对三种算法进行性能测试,结果如下:

暴力枚举耗时:49.719844秒

中心扩展法耗时:0.334019秒

Manacher算法耗时:0.008000秒

测试数据显示,当字符串长度为1000时,暴力枚举的耗时已难以接受。相比之下,中心扩展法效率有大幅提升,而Manacher算法耗时最短,展现了其在大规模数据处理上的显著优势。

本文介绍了Python中求解最长回文子串的算法优化过程,希望能为读者提供学习参考,欢迎继续支持本站获取更多技术内容。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。