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基础教程之基本数据类型和变量声明介绍
Aug 29 Python
Python多线程同步Lock、RLock、Semaphore、Event实例
Nov 21 Python
Python中使用装饰器和元编程实现结构体类实例
Jan 28 Python
Centos Python2 升级到Python3的简单实现
Jun 21 Python
Django应用程序中如何发送电子邮件详解
Feb 04 Python
Python初学时购物车程序练习实例(推荐)
Aug 08 Python
python实现从pdf文件中提取文本,并自动翻译的方法
Nov 28 Python
Python unittest 简单实现参数化的方法
Nov 30 Python
python实现手机销售管理系统
Mar 19 Python
pyqt5对用qt designer设计的窗体实现弹出子窗口的示例
Jun 19 Python
Selenium启动Chrome时配置选项详解
Mar 18 Python
Python使用re模块验证危险字符
May 21 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
Laravel 5.4向IoC容器中添加自定义类的方法示例
2017/08/15 PHP
php处理抢购类功能的高并发请求
2018/02/08 PHP
因str_replace导致的注入问题总结
2019/08/08 PHP
PhpStorm 2020.3:新增开箱即用的PHP 8属性(推荐)
2020/10/30 PHP
PHP加MySQL消息队列深入理解
2021/02/27 PHP
使用 JScript 创建 .exe 或 .dll 文件的方法
2011/07/13 Javascript
js document.write()使用介绍
2014/02/21 Javascript
js判断手机端(Android手机还是iPhone手机)
2015/07/22 Javascript
JS实现的网页背景闪电闪烁效果代码
2015/10/17 Javascript
JavaScript实现广告弹窗效果
2016/08/09 Javascript
AngularJS实现在ng-Options加上index的解决方法
2016/11/03 Javascript
用Vue.js实现监听属性的变化
2016/11/17 Javascript
node.js中EJS 模板快速入门教程
2017/05/08 Javascript
Vue中使用better-scroll实现轮播图组件
2020/03/07 Javascript
以Python的Pyspider为例剖析搜索引擎的网络爬虫实现方法
2015/03/30 Python
Python使用Paramiko模块编写脚本进行远程服务器操作
2016/05/05 Python
Python图形绘制操作之正弦曲线实现方法分析
2017/12/25 Python
Python爬虫获取整个站点中的所有外部链接代码示例
2017/12/26 Python
python矩阵转换为一维数组的实例
2018/06/05 Python
python导入坐标点的具体操作
2019/05/10 Python
Pycharm最新激活码2019(推荐)
2019/12/31 Python
python如何通过pyqt5实现进度条
2020/01/20 Python
TFRecord文件查看包含的所有Features代码
2020/02/17 Python
Django利用elasticsearch(搜索引擎)实现搜索功能
2020/11/26 Python
Python基于template实现字符串替换
2020/11/27 Python
欧洲最大的品牌水上运动服装和设备在线零售商:Wuituit Outlet
2018/05/05 全球购物
手工制作的男士奢华英国鞋和服装之家:Goodwin Smith
2019/06/21 全球购物
应届硕士毕业生自荐信
2014/05/26 职场文书
爱牙日活动总结
2014/08/29 职场文书
实习证明格式范文
2014/10/14 职场文书
升学宴学生答谢词
2015/01/05 职场文书
小学二年级数学教学计划
2015/01/20 职场文书
2015廉洁自律个人总结
2015/02/14 职场文书
自我工作评价范文
2015/03/06 职场文书
Python实现学生管理系统(面向对象版)
2021/06/24 Python
Linux在两个服务器直接传文件的操作方法
2022/08/05 Servers