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中的列表推导浅析
Apr 26 Python
Python中让MySQL查询结果返回字典类型的方法
Aug 22 Python
Python中实现对list做减法操作介绍
Jan 09 Python
Python实现抓取网页生成Excel文件的方法示例
Aug 05 Python
Python模拟登录的多种方法(四种)
Jun 01 Python
使用numpy和PIL进行简单的图像处理方法
Jul 02 Python
Django实现基于类的分页功能
Oct 31 Python
使用python实现数组、链表、队列、栈的方法
Dec 20 Python
PyCharm使用之配置SSH Interpreter的方法步骤
Dec 26 Python
tensorflow 报错unitialized value的解决方法
Feb 06 Python
python用opencv完成图像分割并进行目标物的提取
May 25 Python
numpy array找出符合条件的数并赋值的示例代码
Jun 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
在mysql数据库原有字段后增加新内容
2009/11/26 PHP
gd库图片下载类实现下载网页所有图片的php代码
2012/08/20 PHP
CodeIgniter启用缓存和清除缓存的方法
2014/06/12 PHP
ThinkPHP3.1新特性之动态设置自动完成和自动验证示例
2014/06/19 PHP
[原创]PHP实现逐行删除文件右侧空格的方法
2015/12/25 PHP
谈谈PHP连接Access数据库的注意事项
2016/08/12 PHP
php中序列化与反序列化详解
2017/02/13 PHP
微信公众号开发之获取位置信息php代码
2018/06/13 PHP
PHP按一定比例压缩图片的方法
2018/10/12 PHP
PHP常用函数之base64图片上传功能详解
2019/10/21 PHP
用Javascript同时提交多个Web表单的方法
2009/12/26 Javascript
js 利用image对象实现图片的预加载提高访问速度
2013/03/29 Javascript
使用jQuery判断IE浏览器版本的代码
2014/06/14 Javascript
express的中间件basicAuth详解
2014/12/04 Javascript
JavaScript模拟深蓝vs卡斯帕罗夫的国际象棋对局示例
2015/04/22 Javascript
JavaScript表单验证开发
2016/11/23 Javascript
AngularJS报错$apply already in progress的解决方法分析
2017/01/30 Javascript
BootStrap给table表格的每一行添加一个按钮事件
2017/09/07 Javascript
用React实现一个完整的TodoList的示例代码
2017/10/30 Javascript
微信小程序选择图片和放大预览图片功能
2017/11/02 Javascript
Vue-router 中hash模式和history模式的区别
2018/07/24 Javascript
使用weixin-java-tools完成微信授权登录、微信支付的示例
2018/09/26 Javascript
在vue中使用express-mock搭建mock服务的方法
2018/11/07 Javascript
关于vue里页面的缓存详解
2019/11/04 Javascript
解决 window.onload 被覆盖的问题方法
2020/01/14 Javascript
关于numpy中np.nonzero()函数用法的详解
2017/02/07 Python
Python实现自定义顺序、排列写入数据到Excel的方法
2018/04/23 Python
python time.sleep()是睡眠线程还是进程
2019/07/09 Python
python使用sessions模拟登录淘宝的方式
2019/08/16 Python
英国运动风奢侈品购物网站:Maison De Fashion
2020/08/28 全球购物
澳大利亚家具商店:Freedom
2020/12/17 全球购物
《孔繁森》教学反思
2014/04/17 职场文书
小学生操行评语大全
2014/04/22 职场文书
工厂搬迁方案
2014/05/11 职场文书
2016秋季幼儿园开学寄语
2015/12/03 职场文书
《妈妈别哭,有我在》读后感3篇
2020/01/13 职场文书