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 相关文章推荐
DRF跨域后端解决之django-cors-headers的使用
Jan 27 Python
Python判断变量名是否合法的方法示例
Jan 28 Python
Python 正则表达式 re.match/re.search/re.sub的使用解析
Jul 22 Python
python实现通过flask和前端进行数据收发
Aug 22 Python
python循环输出三角形图案的例子
Nov 22 Python
利用pyecharts读取csv并进行数据统计可视化的实现
Apr 17 Python
python中有函数重载吗
May 28 Python
没编程基础可以学python吗
Jun 17 Python
python使用openpyxl库读写Excel表格的方法(增删改查操作)
May 02 Python
如何利用opencv判断两张图片是否相同详解
Jul 07 Python
Python获取江苏疫情实时数据及爬虫分析
Aug 02 Python
python百行代码实现汉服圈图片爬取
Nov 23 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
从零开始的异世界生活:第二季延期后,B站上架了第二部剧场版
2020/05/06 日漫
php 随机记录mysql rand()造成CPU 100%的解决办法
2010/05/18 PHP
PHP错误抑制符(@)导致引用传参失败Bug的分析
2011/05/02 PHP
php增删改查示例自己写的demo
2013/09/04 PHP
浅谈Eclipse PDT调试PHP程序
2014/06/09 PHP
extjs grid设置某列背景颜色和字体颜色的方法
2010/09/03 Javascript
js克隆对象、数组的常用方法介绍
2013/09/26 Javascript
JavaScript onkeydown事件入门实例(键盘某个按键被按下)
2014/10/17 Javascript
jQuery简单实现提交数据出现loading进度条的方法
2016/03/29 Javascript
JS使用eval()动态创建变量的方法
2016/06/03 Javascript
js给table赋值的实例代码
2016/10/13 Javascript
js中json处理总结之JSON.parse
2016/10/14 Javascript
WebPack基础知识详解
2017/01/16 Javascript
详解React native全局变量的使用(跨组件的通信)
2017/09/07 Javascript
薪资那么高的Web前端必看书单
2017/10/13 Javascript
vue中的适配px2rem示例代码
2018/11/19 Javascript
Vue实现移动端左右滑动效果的方法
2018/11/27 Javascript
详解将微信小程序接口Promise化并使用async函数
2019/08/05 Javascript
vue中实现高德定位功能
2019/12/03 Javascript
js实现多图和单图上传显示
2019/12/18 Javascript
Python的Django框架中的URL配置与松耦合
2015/07/15 Python
Python验证企业工商注册码
2015/10/25 Python
Python爬取当当、京东、亚马逊图书信息代码实例
2017/12/09 Python
Python3使用SMTP发送带附件邮件
2020/06/16 Python
Python绘制正余弦函数图像的方法
2018/08/28 Python
python图的深度优先和广度优先算法实例分析
2019/10/26 Python
Python 实现PS滤镜的旋涡特效
2020/12/03 Python
PyCharm+Miniconda3安装配置教程详解
2021/02/16 Python
HTML5拖拽的简单实例
2016/05/30 HTML / CSS
荷兰和比利时时尚鞋店:Van Dalen
2018/04/23 全球购物
20世纪40年代连衣裙和复古服装:The Seamstress Of Bloomsbury
2018/07/24 全球购物
thinkphp5 redis缓存新增方法实例讲解
2021/03/24 PHP
公证书标准格式
2014/04/10 职场文书
高中班级口号
2014/06/09 职场文书
PyQt5结合QtDesigner实现文本框读写操作
2021/06/11 Python
Vue.js中v-for指令的用法介绍
2022/03/13 Vue.js