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 安装setuptools和pip工具操作方法(必看)
May 22 Python
Python随机读取文件实现实例
May 25 Python
python3利用smtplib通过qq邮箱发送邮件方法示例
Dec 03 Python
Python图形绘制操作之正弦曲线实现方法分析
Dec 25 Python
python利用smtplib实现QQ邮箱发送邮件
May 20 Python
Flask框架Flask-Principal基本用法实例分析
Jul 23 Python
Python 把序列转换为元组的函数tuple方法
Jun 27 Python
Python实现时间序列可视化的方法
Aug 06 Python
python求平均数、方差、中位数的例子
Aug 22 Python
python elasticsearch环境搭建详解
Sep 02 Python
手把手教你安装Windows版本的Tensorflow
Mar 26 Python
Python 如何展开嵌套的序列
Aug 01 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
jQuery 选择器理解
2010/03/16 Javascript
javascript中String类的subString()方法和slice()方法
2011/05/24 Javascript
JS判断不能为空实例代码
2013/11/26 Javascript
js模拟C#中List的简单实例
2014/03/06 Javascript
关于javaScript注册click事件传递参数的不成功问题
2014/07/18 Javascript
jQuery实现炫酷的鼠标轨迹特效
2015/02/01 Javascript
jQuery使用toggleClass方法动态添加删除Class样式的方法
2015/03/26 Javascript
js实现滑动触屏事件监听的方法
2015/05/05 Javascript
JavaScript实现仿网易通行证表单验证
2015/05/25 Javascript
jQuery Validate表单验证插件 添加class属性形式的校验
2016/01/18 Javascript
使用Script元素发送JSONP请求的方法
2016/06/12 Javascript
JavaScript仿flash遮罩动画效果
2016/06/15 Javascript
微信小程序 动态的设置图片的高度和宽度详解及实例代码
2017/02/24 Javascript
React Native预设占位placeholder的使用
2017/09/28 Javascript
浅谈NodeJs之数据库异常处理
2017/10/25 NodeJs
在 React、Vue项目中使用SVG的方法
2018/02/09 Javascript
vuejs简单验证码功能完整示例
2019/01/08 Javascript
让Vue响应Map或Set的变化操作
2020/11/11 Javascript
[01:15:36]加油刀塔第二期网络版
2014/08/09 DOTA
Python实现115网盘自动下载的方法
2014/09/30 Python
PyQt5实现无边框窗口的标题拖动和窗口缩放
2018/04/19 Python
Python面向对象之类和对象属性的增删改查操作示例
2018/12/14 Python
Python3实现取图片中特定的像素替换指定的颜色示例
2019/01/24 Python
对Python中 \r, \n, \r\n的彻底理解
2020/03/06 Python
django自定义非主键自增字段类型详解(auto increment field)
2020/03/30 Python
Python爬取微信小程序通用方法代码实例详解
2020/09/29 Python
html5使用Canvas绘图的使用方法
2017/11/21 HTML / CSS
canvas压缩图片以及卡片制作的方法示例
2018/12/04 HTML / CSS
社区七一党员活动方案
2014/01/25 职场文书
师德学习感言
2014/01/31 职场文书
关于保护环境的建议书
2014/08/26 职场文书
工作保证书怎么写
2015/02/28 职场文书
小学中队活动总结
2015/05/11 职场文书
关于空气污染危害的感想
2015/08/11 职场文书
导游词之西递宏村
2019/12/10 职场文书
win10音频服务未响应怎么解决?win10音频服务未响应未修复的解决方法
2022/08/14 数码科技