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操作CouchDB的方法
Oct 08 Python
Python实现从订阅源下载图片的方法
Mar 11 Python
Python上传package到Pypi(代码简单)
Feb 06 Python
python数据类型判断type与isinstance的区别实例解析
Oct 31 Python
Python模块文件结构代码详解
Feb 03 Python
python读取和保存视频文件
Apr 16 Python
python 定时器,轮询定时器的实例
Feb 20 Python
python实现车牌识别的示例代码
Aug 05 Python
Python图像处理库PIL的ImageEnhance模块使用介绍
Feb 26 Python
利用python实现平稳时间序列的建模方式
Jun 03 Python
Python Pandas list列表数据列拆分成多行的方法实现
Dec 14 Python
python基础之//、/与%的区别详解
Jun 10 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
如何跨站抓取别的站点的页面的补充
2006/10/09 PHP
php中通过数组进行高效随机抽取指定条记录的算法
2013/09/09 PHP
php中namespace use用法实例分析
2016/01/22 PHP
PHP数组实例详解
2016/06/26 PHP
PHP精确到毫秒秒杀倒计时实例详解
2019/03/14 PHP
JavaScript 滚轮事件使用说明
2010/03/07 Javascript
javascript 简单抽屉效果的实现代码
2010/03/09 Javascript
jQuery Lightbox 图片展示插件使用说明
2010/04/25 Javascript
Dom与浏览器兼容性说明
2010/10/25 Javascript
jquery和js实现对div的隐藏和显示方法
2014/09/26 Javascript
jquery 中ajax执行的优先级
2015/06/22 Javascript
基于js实现投票的实例代码
2015/08/04 Javascript
jQuery插件zTree实现删除树节点的方法示例
2017/03/08 Javascript
NodeJS测试框架mocha入门教程
2017/03/28 NodeJs
深入理解vue $refs的基本用法
2017/07/13 Javascript
vue中各组件之间传递数据的方法示例
2017/07/27 Javascript
深入理解 webpack 文件打包机制(小结)
2018/01/08 Javascript
Vue.js实现可配置的登录表单代码详解
2018/03/29 Javascript
快速解决Vue项目在IE浏览器中显示空白的问题
2018/09/04 Javascript
Nodejs监听日志文件的变化的过程解析
2019/08/04 NodeJs
在vue中使用vant TreeSelect分类选择组件操作
2020/11/02 Javascript
js基于canvas实现时钟组件
2021/02/07 Javascript
Python基础之函数用法实例详解
2014/09/10 Python
使用Python脚本实现批量网站存活检测遇到问题及解决方法
2016/10/11 Python
对python借助百度云API对评论进行观点抽取的方法详解
2019/02/21 Python
Python创建或生成列表的操作方法
2019/06/19 Python
HTML5学习心得总结(推荐)
2016/07/08 HTML / CSS
HTML5 Web缓存和运用程序缓存(cookie,session)
2018/01/11 HTML / CSS
美国生日蛋糕店:Bake Me A Wish!
2017/02/08 全球购物
摩托车和ATV零件、配件和服装的首选在线零售商:MotoSport
2017/12/22 全球购物
专注澳大利亚特产和新西兰特产的澳洲中文网:0061澳洲制造
2019/03/24 全球购物
美国价格实惠的在线眼镜网站:Zeelool
2020/12/25 全球购物
食品安全处置方案
2014/06/14 职场文书
2014业务员年终工作总结
2014/12/09 职场文书
董事长年会致辞
2015/07/29 职场文书
python 破解加密zip文件的密码
2021/04/22 Python