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转换字符串为摩尔斯电码的方法
Jul 06 Python
详解Python函数可变参数定义及其参数传递方式
Aug 02 Python
Python实现注册登录系统
Aug 08 Python
django项目运行因中文而乱码报错的几种情况解决
Nov 07 Python
Python实现数据可视化看如何监控你的爬虫状态【推荐】
Aug 10 Python
Python实现简单查找最长子串功能示例
Feb 26 Python
PyCharm搭建Spark开发环境实现第一个pyspark程序
Jun 13 Python
Django之choices选项和富文本编辑器的使用详解
Apr 01 Python
解决pytorch多GPU训练保存的模型,在单GPU环境下加载出错问题
Jun 23 Python
Python configparser模块封装及构造配置文件
Aug 07 Python
Python __slots__的使用方法
Nov 15 Python
pycharm最新激活码有效期至2100年(亲测可用)
Feb 05 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无法访问远程mysql的问题分析及解决
2013/05/16 PHP
php显示页码分页类的封装
2017/06/08 PHP
JS中简单的实现像C#中using功能(有源码下载)
2007/01/09 Javascript
工作需要写的一个js拖拽组件
2011/07/28 Javascript
使用javascript创建快捷方式的简单实例
2013/08/09 Javascript
js跳转页面方法实现汇总
2014/02/11 Javascript
javascript操作excel生成报表全攻略
2014/05/04 Javascript
JavaScript中连接操作Oracle数据库实例
2015/04/02 Javascript
js获取url传值的方法
2015/12/18 Javascript
JavaScript表单验证实例之验证表单项是否为空
2016/01/10 Javascript
深入浅析JavaScript中with语句的理解
2016/05/12 Javascript
原生javascript实现的ajax异步封装功能示例
2016/11/03 Javascript
用jquery的attr方法实现图片切换效果
2017/02/05 Javascript
NodeJS配置HTTPS服务实例分享
2017/02/19 NodeJs
JS实现点击Radio动态更新table数据
2017/07/18 Javascript
记录一篇关于redux-saga的基本使用过程
2018/08/18 Javascript
JavaScript实现多态和继承的封装操作示例
2018/08/20 Javascript
node学习笔记之读写文件与开启第一个web服务器操作示例
2019/05/29 Javascript
layui2.0使用table+laypage实现真分页
2019/07/27 Javascript
微信小程序select下拉框实现源码
2019/11/08 Javascript
vue制作抓娃娃机的示例代码
2020/04/17 Javascript
bootstrapValidator表单校验、更改状态、新增、移除校验字段的实例代码
2020/05/19 Javascript
带你使用webpack快速构建web项目的方法
2020/11/12 Javascript
利用Python中SocketServer 实现客户端与服务器间非阻塞通信
2016/12/15 Python
python 实现红包随机生成算法的简单实例
2017/01/04 Python
python实现人民币大写转换
2018/06/20 Python
Python selenium环境搭建实现过程解析
2020/09/08 Python
酒店门卫岗位职责
2013/12/29 职场文书
会计专业毕业生求职信分享
2014/01/03 职场文书
顶撞领导检讨书
2014/01/29 职场文书
中国合伙人观后感
2015/06/02 职场文书
2016会计专业自荐信范文
2016/01/28 职场文书
2016年法制宣传月活动总结
2016/04/01 职场文书
正确的理解和使用Django信号(Signals)
2021/04/14 Python
Python词云的正确实现方法实例
2021/05/08 Python
React如何创建组件
2021/06/27 Javascript