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 解析XML文件
Apr 15 Python
Python使用MONGODB入门实例
May 11 Python
python正则表达式的使用
Jun 12 Python
python使用mysql的两种使用方式
Mar 07 Python
Python实现自定义函数的5种常见形式分析
Jun 16 Python
python itchat给指定联系人发消息的方法
Jun 11 Python
用python求一重积分和二重积分的例子
Dec 06 Python
Python IDLE或shell中切换路径的操作
Mar 09 Python
利用python实现平稳时间序列的建模方式
Jun 03 Python
Python使用eval函数执行动态标表达式过程详解
Oct 17 Python
Python实现排序方法常见的四种
Jul 15 Python
Python实现提取PDF简历信息并存入Excel
Apr 02 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 静态变量与自定义常量的使用方法
2010/01/26 PHP
PHP函数学习之PHP函数点评
2012/07/05 PHP
深入解析php中的foreach问题
2013/06/30 PHP
PHP使用json_encode函数时不转义中文的解决方法
2014/11/12 PHP
PHP实现上传多文件示例代码
2017/02/20 PHP
PHP使用SWOOLE扩展实现定时同步 MySQL 数据
2017/04/09 PHP
php 后端实现JWT认证方法示例
2018/09/04 PHP
Linux下安装Memcached服务器和客户端与PHP使用示例
2019/04/15 PHP
基于PHP实现生成随机水印图片
2020/12/09 PHP
javascript Array.sort() 跨浏览器下需要考虑的问题
2009/12/07 Javascript
EasyUi datagrid 实现表格分页
2015/02/10 Javascript
Angular中的Promise对象($q介绍)
2015/03/03 Javascript
jqGrid用法汇总(全经典)
2016/06/28 Javascript
jQuery对checkbox 复选框的全选全不选反选的操作
2016/08/09 Javascript
Javascript 判断两个IP是否在同一网段实例代码
2016/11/28 Javascript
React组件之间的通信的实例代码
2017/06/27 Javascript
JavaScript自执行函数和jQuery扩展方法详解
2017/10/27 jQuery
vuejs项目打包之后的首屏加载优化及打包之后出现的问题
2018/04/01 Javascript
微信小程序的mpvue框架快速上手指南
2019/05/15 Javascript
Vue 同步异步存值取值实现案例
2020/08/05 Javascript
js canvas实现五子棋小游戏
2021/01/22 Javascript
[43:36]Liquid vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
部署Python的框架下的web app的详细教程
2015/04/30 Python
使用Python的web.py框架实现类似Django的ORM查询的教程
2015/05/02 Python
python 全文检索引擎详解
2017/04/25 Python
计算机二级python学习教程(2) python语言基本语法元素
2019/05/16 Python
Python微信操控itchat的方法
2019/05/31 Python
python正则表达式匹配IP代码实例
2019/12/28 Python
Python Opencv图像处理基本操作代码详解
2020/08/31 Python
Agoda西班牙:全球特价酒店预订
2017/06/03 全球购物
法国在线药房:DoctiPharma
2020/10/21 全球购物
我们的节日中秋节活动总结
2015/03/23 职场文书
小区保洁员岗位职责
2015/04/10 职场文书
小学班主任教育随笔
2015/08/15 职场文书
go语言中http超时引发的事故解决
2021/06/02 Golang
Python道路车道线检测的实现
2021/06/27 Python