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目录操作之python遍历文件夹后将结果存储为xml
Jan 27 Python
深入讨论Python函数的参数的默认值所引发的问题的原因
Mar 30 Python
django通过ajax发起请求返回JSON格式数据的方法
Jun 04 Python
Python实现SMTP发送邮件详细教程
Mar 02 Python
Python基于tkinter模块实现的改名小工具示例
Jul 27 Python
浅谈numpy数组的几种排序方式
Dec 15 Python
Python实现抓取HTML网页并以PDF文件形式保存的方法
May 08 Python
python实战教程之自动扫雷
Jul 13 Python
基于pandas将类别属性转化为数值属性的方法
Jul 25 Python
python爬虫爬取监控教务系统的思路详解
Jan 08 Python
Python基于read(size)方法读取超大文件
Mar 12 Python
tensorflow从ckpt和从.pb文件读取变量的值方式
May 26 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
目录,文件操作详谈―PHP
2006/11/25 PHP
PHP5中使用DOM控制XML实现代码
2010/05/07 PHP
为IP查询添加GOOGLE地图功能的代码
2010/08/08 PHP
PHP将XML转数组过程详解
2013/11/13 PHP
php图片上传类 附调用方法
2016/05/15 PHP
PHP用continue跳过本次循环中剩余代码的注意点
2017/06/27 PHP
TP5.0框架实现无限极回复功能的方法分析
2019/05/04 PHP
Laravel基础_关于view共享数据的示例讲解
2019/10/14 PHP
Centos7安装swoole扩展操作示例
2020/03/26 PHP
js查找父节点的简单方法
2008/06/28 Javascript
js下用gb2312编码解码实现方法
2009/12/31 Javascript
jQuery的事件委托实例分析
2015/07/15 Javascript
jquery实现简单文字提示效果
2015/12/02 Javascript
Angularjs自定义指令实现三级联动 选择地理位置
2017/02/13 Javascript
vuejs响应用户事件(如点击事件)
2017/03/14 Javascript
javascript与PHP动态往类中添加方法对比
2018/03/21 Javascript
JavaScript实现小球沿正弦曲线运动
2020/09/07 Javascript
微信二次分享报错invalid signature问题及解决方法
2019/04/01 Javascript
python处理中文编码和判断编码示例
2014/02/26 Python
Python字符串中查找子串小技巧
2015/04/10 Python
编写Python脚本来实现最简单的FTP下载的教程
2015/05/04 Python
Python贪吃蛇游戏编写代码
2020/10/26 Python
Python中模块与包有相同名字的处理方法
2017/05/05 Python
python画出三角形外接圆和内切圆的方法
2018/01/25 Python
Python处理中文标点符号大集合
2018/05/14 Python
Python 实例方法、类方法、静态方法的区别与作用
2019/08/14 Python
Python Lambda函数使用总结详解
2019/12/11 Python
Python Des加密解密如何实现软件注册码机器码
2020/01/08 Python
匡威意大利官方商店 :Converse意大利
2018/11/27 全球购物
介绍一下EJB的分类及其各自的功能及应用
2016/08/23 面试题
公司投资建议书
2014/05/16 职场文书
基层党员学习党的群众路线教育实践活动心得体会
2014/11/04 职场文书
师德标兵先进事迹材料
2014/12/19 职场文书
护士个人年度总结范文
2015/02/13 职场文书
创业方案:赚钱的烧烤店该怎样做?
2019/07/05 职场文书
Go语言-为什么返回值为接口类型,却返回结构体
2021/04/24 Golang