python最长回文串算法

作者:熊熊不爱说话 时间:2023-03-05 02:27:37 

给定一个字符串,要求在这个字符串中找到符合回文性质的最长子串。所谓回文性是指诸如 “aba”,"ababa","abba"这类的字符串,当然单个字符以及两个相邻相同字符也满足回文性质。

看到这个问题,最先想到的解决方法自然是暴力枚举,通过枚举字符串所有字串的起点,逐一判断满足回文性的子串,记录长度并更新最长长度。显然这种算法的时间复杂度是很高的,最坏情况可以达到O(N*N)。所以呢,这里提出一个优化的方案,通过枚举字符串子串的中心而不是起点,向两边同时扩散,依然是逐一判断子串的回文性。这种优化算法比之前的算法在最坏的情况下(即只有一种字符的字符串)效率会有很大程度的上升。

由上述的优化方案,我们知道了枚举中心要比枚举起点效率要好,然而这并不是最优的算法。由于枚举中心的算法同时影响的是中心两边的字符,所以我们可以通过枚举中心的左边字符作为中心的子串的回文性判断枚举中心右边的字符作为中心得子串的回文性,这就是manacher算法。

manacher算法思想非常巧妙,首先遍历字符串,假设 i 为枚举中心,则 j (j<i) 为中心的最长回文子串长度发f[j] 便已经求出,此时 j 的影响范围便是[j-f[j]/2,j+f [j]] 。为了使左边的字符 j 对枚举中心右边的影响最大,需要使 j+f[j]/2 最大。找到满足j+f[j]/2最大的 j 之后,若 i 在[j,j+f[j]/2]中,则分两种情况:

1 . i 关于 j 对称的字符i'的影响范围完全包含在j的影响范围内,则由于回文性,i 的影响范围大于等于i'的影响范围,即f[i]>=f[i']

2. 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。

综上1,2,可得f[i]>=min(f[2*j-i],f[j]+2*j-2*i)。由于i右边存在未遍历的字符,因此在此基础上,继续向两边扩展,直到找到最长的回文子串。

若i依然在j+f[j]/2后面,则表示i没有被前面的字符的影响,只能逐一的向两边扩展。

这个算法由于只需遍历一遍字符串,扩展的次数也是有限的,所以时间复杂度可以达到O(N)。

下面是Pthon3的程序,为了检测算法的效率,依然提供最初的暴力枚举算法作为最坏算法的参照。

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.719844s

中心枚举:0.334019s

manacher:0.008000s

由此可见,长度为1000时,暴力枚举的耗时已经无法忍受了,而相比而言,中心枚举在效率上已经有很大幅度的提升,最优的manacher耗时则为更短。

来源:https://blog.csdn.net/backkom_lory/article/details/53896664

标签:python,最长回文串
0
投稿

猜你喜欢

  • Python中print函数简单使用总结

    2022-08-07 19:28:36
  • python如何在word中存储本地图片

    2022-09-13 02:17:53
  • python nohup 实现远程运行不宕机操作

    2023-10-21 02:21:44
  • python分析nignx访问日志脚本分享

    2021-05-22 14:55:14
  • 浅谈numpy中np.array()与np.asarray的区别以及.tolist

    2022-06-06 12:32:10
  • Python函数基础

    2022-09-11 11:36:43
  • 跟老齐学Python之重回函数

    2022-06-29 16:55:43
  • 如何利用Python实现一个论文降重工具

    2021-02-04 08:11:28
  • 详解Visual Studio使用Git忽略不想上传到远程仓库的文件

    2023-10-13 06:42:21
  • IE8 CSS之生成内容

    2008-09-09 22:14:00
  • ASP压缩ACCESS数据库实例

    2009-01-19 11:47:00
  • Python多线程的使用详情

    2023-05-29 15:13:36
  • 还在手动盖楼抽奖?教你用Python实现自动评论盖楼抽奖(一)

    2023-12-26 21:32:41
  • Bootstrap组合上、下拉框简单实现代码

    2024-04-10 11:03:05
  • 人生苦短我用python python如何快速入门?

    2021-06-01 03:57:09
  • Python自动录入ERP系统数据

    2022-03-09 06:05:41
  • 使用matplotlib绘制图例标签中带有公式的图

    2022-07-19 00:40:48
  • python爬虫之urllib,伪装,超时设置,异常处理的方法

    2022-07-23 23:47:10
  • SQL Server 2005数据库还原错误的经典解决方案

    2024-01-21 00:54:56
  • Python 如何展开嵌套的序列

    2022-10-12 03:15:37
  • asp之家 网络编程 m.aspxhome.com