要解决的问题:

给定一个字符串,要求求出这个字符串中的最长的回文串子串。

例子:

cbddba的最长回文子串为 bddb

cbdedba的最长回文子串为dbedb

由上面的例子可以看到,在考虑回文子串的问题时需要考虑奇偶性。因为奇回文关于中心的某个字符对称,而偶回文关于最中心的两个元素之间的间隙对称。

一、动态规划法

在动态规划的思想中,总是希望把问题划分成相关联的子问题;然后从最基本的子问题出发来推导较大的子问题,直到所有的子问题都解决。

首先要看一个较大的子问题与一个较小的子问题之间的关系:

首先建立如下的函数:

那么就能有如下的递推关系:

当p(i+1,j-1)  = true 的时候,如果有si == sj,那么 p(i,j)=true;也就是 abba中的bb为回文串,那么在bb左边是a,在bb右边也是a,相同;所以有abba也是回文串。

形式化表示如下: p(i,j) = p(i+1,j-1) and si==sj    这就建立了较大问题与较小问题之间的关系。

然后考虑基本情况,一个最基本的回文串有两种情况(奇偶性):

(1) 最基本的奇回文,只有一个字符,而且恒成立;形式化表示为 p(i,i) = true

(2)最基本的偶回文,有两个字符,当且仅当两个字符相等的时候成立p(i,j) = (si==sj and j=i+1)

最后获得如下判断一个字符是否为回文串的分段函数:

有了公式,就是用代码实现了;下面给出了我的python实现。

# -*- coding:utf-8 -*-
# Author: Evan Mi# 测试的字符串
str_exp = "babad"
# 用来保存动态规划过程的表 1表示true 0表示false
longest_palindromes = [[-1] * len(str_exp) for i in range(len(str_exp))]
# longest_len 用来保存最长的回文串的长度
longest_len = 1
# 从长度为1的回文子串开始填表
for p_len in range(1, len(str_exp)+1):for i in range(len(str_exp)):j = p_len + i - 1if j < len(str_exp):if i == j:longest_palindromes[i][j] = 1elif j == i + 1 and str_exp[i] == str_exp[j]:longest_palindromes[i][j] = 1longest_len = p_lenelif j > i+1 and longest_palindromes[i+1][j-1] == 1 and str_exp[i] == str_exp[j]:longest_palindromes[i][j] = 1longest_len = p_lenelse:longest_palindromes[i][j] = 0
# 搜索结果表,打印出所有的最优解
for i in range(len(str_exp)):for j in range(len(str_exp)):if longest_palindromes[i][j] == 1 and j-i+1 == longest_len:print(str_exp[i:j+1])

在动态规划中,最最最核心的就是填表了,就以程序中的例子"babad"举例,说明一下填表的过程;

首先我们要填的表是如下的一张表二维表(因为p函数中有i,j两个变量),其中绿色的部分是真实的表格,其他的是我家的解释表头。

填表过程如下:首先填长度为1的;

然后填长度为2的;

接着是长度为3的:

长度为4的:

最后是长度为5的:

填表完成之后,求最优解就是查询了;对于时间复杂度,动态规划的时间复杂度在构建表的过程中的基本操作,所以时间复杂度是O(n^2);空间复杂度,就是上面的二维数组,也是O(n^2)。而且从在空间浪费(主对角线下面的空间没有使用,浪费了一般的空间)。有很多针对空间上的优化方法,下面给出一种空间复杂度为O(1)的算法;

二、空间复杂度为O(1)的算法

该算法的主要思想就遍历所有的字符(下标为i)是以第i个数(对应奇回文)或者第i个数和第i+1个数之间的间隙(对应偶回文)为中心向两边扩展,直到扩展以后不再是回文,那么就停止扩展,如果回文长度比已知的最长回文长,那么记录下该回问的开始位置和结束位置为最长回文;

还是用"babad"来作为例子,过程如下:

代码实现如下:

# -*- coding:utf-8 -*-
# Author: Evan Mi
import mathdef expandAroundCenter(left, right, s):"""从left和right之间开始扩展,如果left==right就是以left/right为中心进行扩展"""rLeft = leftrRight = rightwhile rLeft >= 0 and rRight < len(s) and s[rLeft] == s[rRight]:  # 进行扩展rLeft -= 1rRight += 1"""针对于返回的长度,因为在while循环停止的时候,rLeft和rRight都已经在要求的回文串之外了所以回文串的长度为rRight - rLeft - 1,自己可以画个过程图,一目了然。"""return rRight - rLeft - 1s = "babad"
start = 0
end = 0for i in range(len(s)):odd_len = expandAroundCenter(i, i, s)  # i为中心的扩展even_len = expandAroundCenter(i, i + 1, s)  # i 和 i+1之间的空隙为中心进行扩展lens = max(odd_len, even_len)  # 取得本次扩展的最大值if lens > (end-start+1):  # 如果本次的长度比记录的回文的长度也就是end-start+1大,进行替换# 需要注意的是,已经知道了位置i,不管是以i为中心扩展了长为lens的回文还是# 以i和i+1的空隙为中心扩展了长为lens的回文。下面的start和end的计算方法都成立start = i - math.floor((lens - 1) / 2) end = i + math.floor(lens/2)print(start, ":", end)
print(s[start:end+1])

这里时间复杂度并没有改变,但是我们的空间复杂度变成了O(1)。但是也带来了明显的缺陷,那就是只能求的第一个出现的最优解。 额,如果把 if lens > (end-start+1) 改为 if lens >= (end-start+1),那么能求最后出现的最优解。

这两个算法不论在空间、结果上有什么不同,它们的时间复杂度都是相同的;接下来就分析一下“马拉车”算法,该算法把时间复杂度降到了线性范围内。额,请见下篇博客。

PS:很多人都分析了"马拉车"算法,但是也阻挡不了我征服它的步伐。相信自己对它一定有独到的见解。

求最长回文串-从动态规划到马拉车之路(上)相关推荐

  1. 求最长回文串-从动态规划到马拉车之路(下)

    预备知识: (1)在一个数轴上有两点i和j(i<=j)关于点m对称,那么有 i = 2m-j: 证明: 因为 i<=j 且 i 和 j 关于 m 对称,那么有 (i + j)/ 2 = m ...

  2. 最长回文 HDU - 3068(求最长回文串的长度【马拉车算法Manacher】)

    马拉车算法 Manacher's Algorithm 是用来查找一个字符串的最长回文子串的线性方法,由一个叫 Manacher 的人在 1975 年发明的,这个方法的最大贡献是在于将时间复杂度提升到了 ...

  3. Manacher算法 - 求最长回文串的利器

    求最长回文串的利器 - Manacher算法 Manacher主要是用来求某个字符串的最长回文子串. 不要被manacher这个名字吓倒了,其实manacher算法很简单,也很容易理解,程序短,时间复 ...

  4. hdu 3068 最长回文 (Manacher算法求最长回文串)

    参考博客:Manacher算法--O(n)回文子串算法 - xuanflyer - 博客频道 - CSDN.NET 从队友那里听来的一个算法,O(N)求得每个中心延伸的回文长度.这个算法好像比较偏门, ...

  5. 求最长回文子串——C++ (动态规划+暴力解法)

    声明:本文原题主要来自力扣,记录此博客主要是为自己学习总结,不做任何商业等活动! 一.题目描述 给你一个字符串 s,找到 s 中最长的回文子串. 示例 1: 输入:s = "babad&qu ...

  6. 字符串处理 —— 回文串相关 —— 求最长回文子串

    [暴力枚举] 求最长回文串最容易的方法就是暴力枚举,求出字符串的每一个子串,然后判断是不是回文,找到最长的那个回文串 求每一个子串的时间复杂度为 O(N^2),判断一个子串是不是回文时间复杂度为 O( ...

  7. python求最大回文数_python最长回文串算法

    给定一个字符串,要求在这个字符串中找到符合回文性质的最长子串.所谓回文性是指诸如 "aba","ababa","abba"这类的字符串,当然 ...

  8. 判断回文串,最长回文串方法

    1.判断回文串 回文串就是从左看与从右看都是一样的字符串,例如abcba,acddca 判断一个字符串是否为回文串:如判断s=abcdcba是否为回文串,只要看s以中间位分界线,s的左右两边是否相等即 ...

  9. 最长回文串--动态规划

    最长回文串–动态规划 参考:https://writings.sh/post/algorithm-longest-palindromic-substring class Solution {publi ...

最新文章

  1. 各种梯度下降 bgd sgd mbgd adam
  2. windows命令行无法启动redis_Win10 3分钟简单、快速安装Redis
  3. CodeForces - 1400F x-prime Substrings(AC自动机+dp)
  4. char 类型的常数_CHAR_MAX常数,带C ++示例
  5. csv文件python是怎么输入的,python怎么读取和写入csv文件
  6. 关于UNIX功能测试宏
  7. java实现视频格式转换
  8. java通过LocalDateTime获取上周几
  9. SAP ABAP MOVE 及 CORRESPONDING 7.4版本新用法
  10. NFormer: robust person re-identification with neighbor transformer
  11. 查询宇宙生命的家谱--TaxonKit工具详解
  12. mysql中文日期转换_mysql 日期转换
  13. 哇!8款帮你轻松瘦脸的美食
  14. 外贸客户来源的渠道有哪些?
  15. Cookie获取问题:ajax方法后端只获取到一个Cookie,Request无法获取到自定义的Cookie
  16. linux命令对两个文件求差集、交集、并集
  17. R语言ineq算基尼系数_科学网—一招搞定泰尔指数及其分解 - 王庆喜的博文
  18. MYSQL课程设计——图书管理系统(一)
  19. 入离职管理系统——类的抽取和注册登录功能
  20. C语言移位的一些理解>>

热门文章

  1. 实测实量数据表格_建筑工程质量实测实量操作手册,130页PPT下载!
  2. 怎么读取can报文_【案例】东风天龙“仪表未收到EECU报文”
  3. python发布_python网站发布
  4. Connection to @localhost failed. [08001] Could not create connection to database server. Attempt
  5. java - 求a+aa+aaa+aa...a之和
  6. python配色_python语言再次解决文章配色难题
  7. show index mysql_MySQL SHOW INDEX语法的实际应用
  8. youcans 的 OpenCV 学习课—5.图像的几何变换
  9. Python基础项目实践之:面向对象方法模拟简单计算器
  10. python基础课程5(看代码看注释)--numpy