Python实现常见的回文字符串算法


Posted in Python onNovember 14, 2018

回文

利用python 自带的翻转 函数 reversed()

def is_plalindrome(string):  return string == ''.join(list(reversed(string)))`

自己实现

def is_plalindrome(string):
  string = list(string)
  length = len(string)
  left = 0
  right = length - 1
  while left < right:
    if string[left] != string[right]:
      return False
    left += 1
    right -= 1
  return True

最长的回文子串

暴力破解

暴力破解,枚举所有的子串,对每个子串判断是否为回文, 时间复杂度为 O(n^3)

动态规划

def solution(s):
  s = list(s)
  l = len(s)
  dp = [[0] * l for i in range(l)]
  for i in range(l):
    dp[i][i] = True
    # 当 k = 2时要用到
    dp[i][i - 1] = True
  resLeft = 0
  resRight = 0
  # 枚举子串的长度
  for k in range(2, l+1):
    # 子串的起始位置
    for i in range(0, l-k+1):
      j = i + k - 1
      if s[i] == s[j] and dp[i + 1][j - 1]:
        dp[i][j] = True
        # 保存最长的回文起点和终点
        if resRight - resLeft + 1 < k:
          resLeft = i
          resRight = j
  return ''.join(s[resLeft:resRight+1])

时间复杂度为 O(n^2), 空间复杂度为 O(n^2)

Manacher 算法

Manacher 算法首先对字符串做一个预处理,使得所有的串都是奇数长度, 插入的是同样的符号且符号不存在与原串中,串的回文性不受影响

aba => #a#b#a#abab => #a#b#a#b#`

我们把回文串中最右位置与其对称轴的距离称为回文半径,Manacher 算法定义了一个回文半径数组 RL,RL[i]表示以第 i 个字符为对称轴的回文半径,对于上面得到的插入分隔符的串来说,我们可以得到 RL数组

char: # a # b # a #
RL:  1 2 1 4 1 2 1
RL-1: 0 1 0 3 0 1 0
i:   0 1 2 3 4 5 6
char: # a # b # a # b #
RL:  1 2 1 4 1 4 1 2 1
RL-1: 0 1 0 3 0 3 0 1 0
i:  0 1 2 3 4 5 6 7 8

我们还求了 RL[i] - 1: 我们发现 RL[i] -1 正好是初始字符串中以位置i 为对称轴的最长回文长度

所以下面就是重点如何求得 RL 数组了, 可以参考这篇 文章 (讲得比较清晰)

下面是算法实现

def manacher(preS):
  s = '#' + '#'.join(preS) + '#'
  l = len(s)
  RL = [0] * l
  maxRight = pos = maxLen = 0
  for i in range(l):
    if i < maxRight:
      RL[i] = min(RL[2*pos - i], maxRight-i)
    else:
      RL[i] = 1
    while i - RL[i] >= 0 and i + RL[i] < l and s[i - RL[i]] == s[i + RL[i]]:
      RL[i] += 1
    if i + RL[i] - 1 > maxRight:
      maxRight = i + RL[i] - 1
      pos = i
  maxLen = max(RL)
  idx = RL.index(maxLen)
  sub = s[idx - maxLen + 1: idx + maxLen]
  return sub.replace('#', '')

空间复杂度:借助了一个辅助数组,空间复杂度为 O(n)

时间复杂度:尽管内层存在循环,但是内层循环只对尚未匹配的部分进行,对于每一个字符来说,只会进行一次,所以时间复杂度是 O(n)

最长回文前缀

所谓前缀,就是以第一个字符开始

下面的最长回文前缀

abbabbc => abbc
abababb => ababa
sogou => s

将原串逆转,那么问题就转变为求原串的前缀和逆串后缀 相等且长度最大的值 , 这个问题其实就是 KMP 算法 中的 next 数组的求解了

具体求解: 将原串逆转并拼接到原串中, 以'#' 分隔原串和逆转避免内部字符串干扰。

def longest_palindrome_prefix(s):
  if not s:
    return 0
  s = s + '#' + s[::-1] + '$'
  i = 0
  j = -1
  nt = [0] * len(s)
  nt[0] = -1
  while i < len(s) - 1:
    if j == -1 or s[i] == s[j]:
      i += 1
      j += 1
      nt[i] = j
    else:
      j = nt[j]
  return nt[len(s) - 1]

添加字符生成最短回文字符串

这道题其实跟上面基本是一样的,

实例:

aacecaaa -> aaacecaaa # 添加 a
abcd -> dcbabcd # 添加 dcb

我们先求字符串的最长回文前缀, 然后剩余的字符串逆转并拼接到字符串的头部即是问题所求

def solution(s):
  length = longest_palindrome_prefix(s)
  return s[length:][::-1] + s

最长回文子序列

动态规划法

  • dp[i][j] 表示子序列 s[i..j] 中存在的最长回文子序列长度
  • 初始化dp[i][i] = 1
  • 当 s[i] == s[j] 为 true 时,dp[i][j] = dp[i+1][j - 1] + 2
  • 当 s[i] == s[j] 为 false 时,dp[i][j] = max(dp[i+1][j], dp[i][j - 1])
# 求得最长回文子序列的长度
def solution(s):
  l = len(s)
  dp = [[0] * l for i in range(l)]
  for i in range(l):
    dp[i][i] = 1
  # 枚举子串的长度
  for k in range(2, l+1):
    # 枚举子串的起始位置
    for i in range(0, l-k+1):
      j = i + k - 1
      if s[i] == s[j]:
        dp[i][j] = dp[i + 1][j - 1] + 2
      else:
        dp[i][j] = max(dp[i][j - 1], dp[i + 1][j])
  return dp[0][l-1]

时间复杂度为 O(n^2), 空间复杂度为 O(n^2)

总结

以上所述是小编给大家介绍的Python实现常见的回文字符串算法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
python访问sqlserver示例
Feb 10 Python
python使用webbrowser浏览指定url的方法
Apr 04 Python
Python中用Spark模块的使用教程
Apr 13 Python
深入理解Python爬虫代理池服务
Feb 28 Python
Python Json模块中dumps、loads、dump、load函数介绍
May 15 Python
python使用pipeline批量读写redis的方法
Feb 18 Python
python中比较两个列表的实例方法
Jul 04 Python
Python学习笔记之函数的参数和返回值的使用
Nov 20 Python
Python利用FFT进行简单滤波的实现
Feb 26 Python
利用python 下载bilibili视频
Nov 13 Python
浅析Python的命名空间与作用域
Nov 25 Python
pandas按照列的值排序(某一列或者多列)
Dec 13 Python
Python 单元测试(unittest)的使用小结
Nov 14 #Python
python for循环输入一个矩阵的实例
Nov 14 #Python
python获取中文字符串长度的方法
Nov 14 #Python
对python插入数据库和生成插入sql的示例讲解
Nov 14 #Python
python正向最大匹配分词和逆向最大匹配分词的实例
Nov 14 #Python
对python中的乘法dot和对应分量相乘multiply详解
Nov 14 #Python
在python中实现对list求和及求积
Nov 14 #Python
You might like
DC四月将推出百页特刊漫画 纪念小丑诞生80周年
2020/04/09 欧美动漫
php 无限级 SelectTree 类
2009/05/19 PHP
献给php初学者(入门学习经验谈)
2010/10/12 PHP
php桥接模式应用案例分析
2019/10/23 PHP
如何实现iframe(嵌入式帧)的自适应高度
2006/07/26 Javascript
详解Wondows下Node.js使用MongoDB的环境配置
2016/03/01 Javascript
Node.js操作Firebird数据库教程
2016/03/04 Javascript
JS 面向对象之继承---多种组合继承详解
2016/07/10 Javascript
JavaScript实现翻页功能(附效果图)
2017/02/16 Javascript
VueJS如何引入css或者less文件的一些坑
2017/04/25 Javascript
详解项目升级到vue-cli3的正确姿势
2019/01/28 Javascript
JavaScript常用内置对象用法分析
2019/07/09 Javascript
angular8.5集成TinyMce5的使用和详细配置(推荐)
2020/11/16 Javascript
[01:34]完美“圣”典宣传片震撼发布,12.17与你不见不散
2016/12/16 DOTA
[01:08:17]2018DOTA2亚洲邀请赛3月29日 小组赛B组 EG VS VGJ.T
2018/03/30 DOTA
Python函数式编程指南(四):生成器详解
2015/06/24 Python
python中set常用操作汇总
2016/06/30 Python
python实现折半查找和归并排序算法
2017/04/14 Python
Python中列表list以及list与数组array的相互转换实现方法
2017/09/22 Python
Python实现PS滤镜碎片特效功能示例
2018/01/24 Python
对python判断是否回文数的实例详解
2019/02/08 Python
Pycharm激活方法及详细教程(详细且实用)
2020/05/12 Python
Keras在训练期间可视化训练误差和测试误差实例
2020/06/16 Python
Django xadmin安装及使用详解
2020/10/26 Python
Python模拟登录requests.Session应用详解
2020/11/17 Python
CSS3的颜色渐变效果的示例代码
2017/09/29 HTML / CSS
Soft Cotton捷克:来自爱琴海棉花的浴袍
2017/02/01 全球购物
酒店led欢迎词
2014/01/09 职场文书
高中地理教学反思
2014/01/29 职场文书
思想品德自我评价
2014/02/04 职场文书
服装行业创业计划书范文
2014/02/05 职场文书
爱国主义演讲稿
2014/05/07 职场文书
好听的队名和口号
2014/06/09 职场文书
暑期社会实践新闻稿
2015/07/17 职场文书
决心书格式范文
2015/09/23 职场文书
《辉夜大小姐想让我告白》第三季正式预告
2022/03/20 日漫