python实现求最长回文子串长度


Posted in Python onJanuary 22, 2018

给定一个字符串,求它最长的回文子串长度,例如输入字符串'35534321',它的最长回文子串是'3553',所以返回4。

最容易想到的办法是枚举出所有的子串,然后一一判断是否为回文串,返回最长的回文子串长度。不用我说,枚举实现的耗时是我们无法忍受的。那么有没有高效查找回文子串的方法呢?答案当然是肯定的,那就是中心扩展法,选择一个元素作为中心,然后向外发散的寻找以该元素为圆心的最大回文子串。但是又出现了新的问题,回文子串的长度即可能是基数,也可能好是偶数,对于长度为偶数的回文子串来说是不存在中心元素的。那是否有一种办法能将奇偶长度的子串归为一类,统一使用中心扩展法呢?它就是manacher算法,在原字符串中插入特殊字符,例如插入#后原字符串变成'#3#5#5#3#4#3#2#1#'。现在我们对新字符串使用中心扩展发即可,中心扩展法得到的半径就是子串的长度。

现在实现思路已经明确了,先转化字符串'35534321'  ---->  '#3#5#5#3#4#3#2#1#',然后求出以每个元素为中心的最长回文子串的长度。以下给出python实现:

#!/usr/bin/python
# -*- coding: utf-8 -*-

def max_substr(string):
  s_list = [s for s in string]
  string = '#' + '#'.join(s_list) + '#'
  max_length = 0
  length = len(string)
  for index in range(0, length):
    r_length = get_length(string, index)
    if max_length < r_length:
      max_length = r_length
  return max_length

def get_length(string, index):
  # 循环求出index为中心的最长回文字串
  length = 0
  r_ = len(string)
  for i in range(1,index+1):
    if index+i < r_ and string[index-i] == string[index+i]:
      length += 1
    else:
      break
  return length

if __name__ == "__main__":
  result = max_substr("35534321")
  print result

功能已经实现了,经过测试也没有bug,但是我们静下心来想一想,目前的解法是否还有优化空间呢?根据目前的解法,我们求出了‘35534321‘中每个元素中心的最大回文子串。当遍历到'4'时,我们已经知道目前最长的回文子串的长度max_length是4,这是我们求出了以4为中心的最长回文子串长度是3,它比max_length要小,所以我们不更新max_length。换句话说,我们计算以4为中心的最长回文字串长度是做了无用功。这就是我们要优化的地方,既然某个元素的最长的回文子串长度并没有超过max_length,我们就没有必要计算它的最长回文子串,在遍历一个新的元素时,我们要优先判断以它为中心的回文子串的长度是否能超越max_length,如果不能超过,就继续遍历下一个元素。以下是优化后的实现:

#!/usr/bin/python
# -*- coding: utf-8 -*-

def max_substr(string):
  s_list = [s for s in string]
  string = '#' + '#'.join(s_list) + '#'
  max_length = 0
  length = len(string)
  for index in range(0, length):
    r_length = get_length2(string, index, max_length)
    if max_length < r_length:
      max_length = r_length
  return max_length

def get_length2(string, index, max_length):
  # 基于已知的最长字串求最长字串
  # 1.中心+最大半径超出字符串范围, return
  r_ = len(string)
  if index + max_length > r_:
    return max_length

  # 2.无法超越最大半径, return
  l_string = string[index - max_length + 1 : index + 1]
  r_string = string[index : index + max_length]
  if l_string != r_string[::-1]:
    return max_length

  # 3.计算新的最大半径
  result = max_length
  for i in range(max_length, r_):
    if index-i >= 0 and index+i < r_ and string[index-i] == string[index+i]:
      result += 1
    else:
      break
  return result - 1

if __name__ == "__main__":
  result = max_substr("35534321")
  print result

那么速度到底提升了多少呢,以字符串1000个‘1'为例,优化前的算法执行时间为0.239018201828,优化后为0.0180191993713,速度提升了10倍左右

/usr/bin/python /Users/hakuippei/PycharmProjects/untitled/the_method_of_programming.py
0.239018201828
0.0180191993713

再给大家分享一个实例:

#!usr/bin/env python
#encoding:utf-8

'''
__Author__:沂水寒城
功能:寻找最长回文子序列
'''

def slice_window(one_str,w=1):
  '''
  滑窗函数
  '''
  res_list=[]
  for i in range(0,len(one_str)-w+1):
    res_list.append(one_str[i:i+w])
  return res_list


def is_huiwen(one_str_list): 
  '''
  输入一个字符串列表,判断是否为回文序列 
  ''' 
  if len(one_str_list)==1: 
    return True  
  else: 
    half=len(one_str_list)/2 
    if len(one_str_list)%2==0: 
      first_list=one_str_list[:half] 
      second_list=one_str_list[half:] 
    else: 
      first_list=one_str_list[:half] 
      second_list=one_str_list[half+1:] 
    if first_list==second_list[::-1]: 
      return True  
    else: 
      return False 


def find_longest_sub_palindrome_str(one_str):
  '''
  主函数,寻找最长回文子序列
  '''
  all_sub=[]
  for i in range(1,len(one_str)):
    all_sub+=slice_window(one_str,i)
  all_sub.append(one_str)
  new_list=[]
  for one in all_sub:
    if is_huiwen(list(one)):
      new_list.append(one)
  new_list.sort(lambda x,y:cmp(len(x),len(y)),reverse=True)
  print new_list[0]


if __name__ == '__main__':
  one_str_list=['uabcdcbaop','abcba','dmfdkgbbfdlg','mnfkabcbadk']
  for one_str in one_str_list:
    find_longest_sub_palindrome_str(one_str)

结果如下:

abcdcba 
abcba 
bb 
abcba 
[Finished in 0.3s]
Python 相关文章推荐
Python GAE、Django导出Excel的方法
Nov 24 Python
Python 统计字数的思路详解
May 08 Python
python使用epoll实现服务端的方法
Oct 16 Python
python实现爬山算法的思路详解
Apr 09 Python
python3中eval函数用法使用简介
Aug 02 Python
python实现图片压缩代码实例
Aug 12 Python
详解Python可视化神器Yellowbrick使用
Nov 11 Python
python中的subprocess.Popen()使用详解
Dec 25 Python
基于python和flask实现http接口过程解析
Jun 15 Python
手把手教你如何用Pycharm2020.1.1配置远程连接的详细步骤
Aug 07 Python
8g内存用python读取10文件_面试题-python 如何读取一个大于 10G 的txt文件?
May 28 Python
Python编程编写完善的命令行工具
Sep 15 Python
Python获取本机所有网卡ip,掩码和广播地址实例代码
Jan 22 #Python
Linux CentOS7下安装python3 的方法
Jan 21 #Python
简述Python2与Python3的不同点
Jan 21 #Python
手把手教你用python抢票回家过年(代码简单)
Jan 21 #Python
分析Python中解析构建数据知识
Jan 20 #Python
学习Python selenium自动化网页抓取器
Jan 20 #Python
python使用pil库实现图片合成实例代码
Jan 20 #Python
You might like
Mysql数据库操作类( 1127版,提供源码下载 )
2010/12/02 PHP
PHP5.3的垃圾回收机制(动态存储分配方案)深入理解
2012/12/10 PHP
微信公众平台开发关注及取消关注事件的方法
2014/12/23 PHP
php将12小时制转换成24小时制的方法
2015/03/31 PHP
PHP的伪随机数与真随机数详解
2015/05/27 PHP
PHP 序列化和反序列化函数实例详解
2020/07/18 PHP
javascript 获取select下拉列表值的代码
2009/09/07 Javascript
javascript 获取url参数和script标签中获取url参数函数代码
2010/01/22 Javascript
jQuery 源码分析笔记(2) 变量列表
2011/05/28 Javascript
Javascript学习笔记 delete运算符
2011/09/13 Javascript
javascript 原型链维护和继承详解
2014/11/26 Javascript
Javascript中神奇的this
2016/01/20 Javascript
不定义JQuery插件 不要说会JQuery
2016/03/07 Javascript
使用JS实现图片展示瀑布流效果的实例代码
2016/09/12 Javascript
Bootstrap实现带暂停功能的轮播组件(推荐)
2016/11/25 Javascript
使用ionic切换页面卡顿的解决方法
2016/12/16 Javascript
Bootstrap源码解读标签、徽章、缩略图和警示框(8)
2016/12/26 Javascript
vue2.0设置proxyTable使用axios进行跨域请求的方法
2017/10/19 Javascript
React Native AsyncStorage本地存储工具类
2017/10/24 Javascript
vue.js与element-ui实现菜单树形结构的解决方法
2018/04/21 Javascript
详解vue数组遍历方法forEach和map的原理解析和实际应用
2018/11/15 Javascript
原生javascript自定义input[type=radio]效果示例
2019/08/27 Javascript
python读取mysql数据绘制条形图
2020/03/25 Python
深入浅析Python代码规范性检测
2020/07/31 Python
HTML5中的Scoped属性使用实例
2014/04/23 HTML / CSS
英国Amara家居法国网站:家居装饰,现代装饰和豪华礼品
2016/12/15 全球购物
高分子材料与工程专业个人求职信
2013/12/15 职场文书
生产部统计员岗位职责
2014/01/05 职场文书
新闻专业学生的自我评价
2014/02/13 职场文书
高中教师考核方案
2014/05/18 职场文书
书法大赛策划方案
2014/06/04 职场文书
大学生安全责任书
2014/07/25 职场文书
2014年小学生迎国庆65周年演讲稿
2014/09/27 职场文书
2019年入党思想汇报
2019/03/25 职场文书
Mysql数据库表中为什么有索引却没有提高查询速度
2022/02/24 MySQL
windows10 家庭版下FTP服务器搭建教程
2022/08/05 Servers