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 相关文章推荐
python3实现域名查询和whois查询功能
Jun 21 Python
python一行sql太长折成多行并且有多个参数的方法
Jul 19 Python
Python类的继承、多态及获取对象信息操作详解
Feb 28 Python
python对象与json相互转换的方法
May 07 Python
flask框架自定义过滤器示例【markdown文件读取和展示功能】
Nov 08 Python
使用Python进行防病毒免杀解析
Dec 13 Python
Python多线程Threading、子线程与守护线程实例详解
Mar 24 Python
Python sql注入 过滤字符串的非法字符实例
Apr 03 Python
Python configparser模块操作代码实例
Jun 08 Python
python数据类型强制转换实例详解
Jun 22 Python
pygame面向对象的飞行小鸟实现(Flappy bird)
Apr 01 Python
Tensorflow与RNN、双向LSTM等的踩坑记录及解决
May 31 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/10/09 PHP
PHP的Yii框架中View视图的使用进阶
2016/03/29 PHP
PHP中一个有趣的preg_replace函数详解
2018/08/15 PHP
IE6不能修改NAME问题的解决方法
2010/09/03 Javascript
JavaScript SetInterval与setTimeout使用方法详解
2013/11/15 Javascript
chrome下jq width()方法取值为0的解决方法
2014/05/26 Javascript
js与css实现弹出层覆盖整个页面的方法
2014/12/13 Javascript
jQuery中:submit选择器用法实例
2015/01/03 Javascript
jQuery实现鼠标悬停显示提示信息窗口的方法
2015/04/30 Javascript
jQuery Validate 校验多个相同name的方法
2017/05/18 jQuery
nodejs中函数的调用实例详解
2018/10/31 NodeJs
基于Webpack4和React hooks搭建项目的方法
2019/02/05 Javascript
在vue中使用setInterval的方法示例
2019/04/16 Javascript
Node.js 获取微信JS-SDK CONFIG的方法示例
2019/05/21 Javascript
vue 自定指令生成uuid滚动监听达到tab表格吸顶效果的代码
2020/09/16 Javascript
python使用PyV8执行javascript代码示例分享
2013/12/04 Python
Windows下PyMongo下载及安装教程
2015/04/27 Python
详细讲解Python中的文件I/O操作
2015/05/24 Python
基于python进行桶排序与基数排序的总结
2018/05/29 Python
详解PyCharm配置Anaconda的艰难心路历程
2018/08/13 Python
在tensorflow中设置使用某一块GPU、多GPU、CPU的操作
2020/02/07 Python
python GUI库图形界面开发之PyQt5不规则窗口实现与显示GIF动画的详细方法与实例
2020/03/09 Python
Django日志及中间件模块应用案例
2020/09/10 Python
python 爬取百度文库并下载(免费文章限定)
2020/12/04 Python
英国最出名高街品牌:Forever Unique
2018/02/24 全球购物
Falconeri美国官网:由羊绒和羊毛制成的针织服装
2018/04/08 全球购物
阿联酋优惠券服务:Living Kool
2019/12/12 全球购物
100%羊绒:NakedCashmere
2020/08/26 全球购物
广州某公司软件工程师面试题
2014/12/22 面试题
广告学专业应届生求职信
2013/10/01 职场文书
家长写给孩子的评语
2014/04/18 职场文书
五年级学生评语
2014/04/22 职场文书
法制教育演讲稿
2014/09/10 职场文书
建筑技术负责人岗位职责
2015/04/13 职场文书
高中运动会前导词
2015/07/20 职场文书
假如给我三天光明:舟逆水而行,人遇挫而达 
2019/10/29 职场文书