2019独角兽企业重金招聘Python工程师标准>>>

问题描述:

    给定一个字符串S=A1A2...An,要求找出其最长回文子串(Longest Palindromic Substring)。所谓回文子串就是S的某个子串Ai...Aj为回文。例如,对字符串S=abcdcbeba,它的回文子串有:bcdcb,cdc,beb,满足题目要求的最长回文子串为bcdcb。

推理思路:

1.由于回文可能由奇数个字符组成,也可能由偶数个字符组成。对奇数回文的处理比较直观,只需要以某个字符为中心,依次向两边扩展即可。因此,我们可以通过如下方式把对偶数回文的处理转换成对奇数回文的处理:在字符边界添加特殊符号。例如,对字符串aba,预处理后变成#a#b#a#;对字符串abba,预处理后变成#a#b#b#a。可以看出,不管是奇数回文,还是偶数回文,在与处理后都变成奇数回文。在找出与预处理后字符串的最长回文后,只需要去除所有的#即为源字符串的最长回文。

2.对寻找字符串某类子串的问题,最简单直观的想法就是穷举出所有子串一一进行判别。这里也不例外,当然时间复杂度也很高,为O(n^3)。

3.对该问题,我们可以进行一定程度的简化处理。既然回文是一种特殊的字符串,我们可以以源字符串的每个字符为中心,依次寻找出最长回文子串P0, P1,...,Pn。这些最长回文子串中的最长串Pi = max(P1, P2,...,Pn)即为所求。请看源码:

string find_lps_native(const string &str)
{int center = 0, max_len = 0;for(int i = 1; i < str.length()-1; ++i){int j = 1;//以str[i]为中心,依次向两边扩展,寻找最长回文Piwhile(i+j < str.length() && i-j >= 0 && str[i+j] == str[i-j])++j;--j;if(j > 1 && j > max_len){center = i;max_len = j;}}return str.substr(center-max_len, (max_len << 1) + 1);
}

4.可以看出,上面做法的复杂度为O(n^2)。相比穷举字符串的做法,已经降低了一个量级的复杂度。但是仔细想想,上面的算法还有改进空间吗?当然有!而且改进后能够把复杂度降低到O(n)!这就是大名鼎鼎的 Manacher’s Algorithm。请看下文分析:

举例说明:对字符串S=abcdcba而言,最长回文子串是以d为中心,半径为3的子串。当我们采用上面的做法分别求出以S[1]=a, S[2]=b, S[3]=c, S[4]=d为中心的最长回文子串后,对S[5]=c,S[6]=b...还需要一一进行扩展求吗?答案是NO。因为我们已经找到以d为中心,半径为3的回文了,S[5]与S[3],S[6]与S[2]...,以S[4]为对称中心。因此,在以S[5],S[6]为中心扩展找回文串时,可以利用已经找到的S[3],S[2]的相关信息直接进行一定步长的偏移,这样就减少了比较的次数(回想一下KMP中next数组的思想)。优化的思想找到了,我们先看代码:

string find_lps_advance(const string &str)
{//find radius of all charactersvector<int> p(str.length(), 0);int idx = 1, max = 0;for(int i = 1; i < str.length()-1; ++i){if(max > i){p[i] = p[(idx << 1) - i] < (max - i) ? p[(idx << 1) - i]:(max - i);}while(str[i+p[i]+1] == str[i-p[i]-1])p[i] += 1;if(i + p[i] > max){idx = i;max = i+p[i];}}// find the character which has max radiusint center = 0, radius = 0;for(int i = 0; i < p.size(); ++i){if(p[i] > radius){center = i;radius = p[i];}}return str.substr(center-radius, (radius << 1) + 1);
}

这里进行简单的解释:上述代码中有三个主要变量,它们代表的意义分别是:

p:以S[i]为中心的最长回文串的半径为p[i]。

idx:已经找出的能够右延伸最远距离的回文子串的起始位置。

max:已经找出的能够右延伸最远距离的回文子串的结束位置。

算法的主要思想是:先找出所有的p[i],最大的p[i]即为所求。在求p[j] (j>i)时,利用已经求出的p[i]减少比较次数。

代码中比较关键的一句是:

 p[i] = p[(idx << 1) - i] < (max - i) ? p[(idx << 1) - i]:(max - i);

在求p[i]时,如果max>i,则表明已经求出的最长回文中包含了p[i],那么与p[i]关于idx对称的p[ (idx << 1) - i]的最长回文子串可以提供一定的信息。看了两幅图大概就明白什么意思了:

求二者的最小值是因为当前能够获取的信息都来自max的左侧,需要进一步比较,求出以S[i]为中心的最长回文串。

5.除了上述的几种做法外,还可以利用动态规划以及后缀树来进行求解。下次进行介绍。

结束行文之前,补充一句,对于字符串类的问题,建议多画一画,寻找其中的规律。

参考文献:1.http://www.akalin.cx/longest-palindrome-linear-time

转载于:https://my.oschina.net/pathenon/blog/63575

字符串系列之最长回文子串相关推荐

  1. [动态规划|字符串] leetcode 5 最长回文子串

    [动态规划|字符串] leetcode 5 最长回文子串 1.题目 题目链接 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例1: 输入: "b ...

  2. 统计5个字符串回文个数c语言,第一章 字符串 – 1.5 最长回文子串 - 编程之法:面试和算法心得...

    最长回文子串 题目描述 给定一个字符串,求它的最长回文子串的长度. 分析与解法 最容易想到的办法是枚举所有的子串,分别判断其是否为回文.这个思路初看起来是正确的,但却做了很多无用功,如果一个长的子串包 ...

  3. 【LeetCode系列】最长回文子串(双指针中心扩散)与可怜的小猪(老鼠毒药问题)

    ⭐️前面的话⭐️ 本篇文章介绍来自牛客试题广场的两道题题解,分别为[最长回文子串]和[可怜的小猪],展示语言java.

  4. 如何找到字符串中的最长回文子串?

    作者 | channingbreeze 责编 | 胡巍巍 小史是一个应届生,虽然学的是电子专业,但是自己业余时间看了很多互联网与编程方面的书,一心想进BAT互联网公司.可是努力了很久,别说BAT了,连 ...

  5. 【字符串】最长回文子串 ( 动态规划算法 ) ★

    文章目录 一.回文串.子串.子序列 二.最长回文子串 1.动态规划算法 2.动态规划算法代码示例 一.回文串.子串.子序列 " 回文串 ( Palindrome ) " 是 正反都 ...

  6. Codeup-问题 A: 【字符串】最长回文子串

    题目描述 输入一个字符串,求出其中最长的回文子串.子串的含义是:在原串中连续出现的字符串片段.回文的含义是:正着看和倒着看相同.如abba和yyxyy.在判断回文时,应该忽略所有标点符号和空格,且忽略 ...

  7. 问题 A: 【字符串】最长回文子串

    题目描述 输入一个字符串,求出其中最长的回文子串.子串的含义是:在原串中连续出现的字符串片段.回文的含义是:正着看和倒着看相同.如abba和yyxyy.在判断回文时,应该忽略所有标点符号和空格,且忽略 ...

  8. 算法笔记-问题 A: 【字符串】最长回文子串

    问题 A: [字符串]最长回文子串 题目描述 输入一个字符串,求出其中最长的回文子串.子串的含义是:在原串中连续出现的字符串片段.回文的含义是:正着看和倒着看相同.如abba和yyxyy.在判断回文时 ...

  9. Manacher 求最长回文子串算法

    Manacher算法,是由一个叫Manacher的人在1975年发明的,可以在$O(n)$的时间复杂度里求出一个字符串中的最长回文子串. 例如这两个回文串"level"." ...

最新文章

  1. Android UI开发第一篇——android的九宫格式实现
  2. 让Double类型完整显示,不用科学计数法显示E(Java)
  3. uvalive4744(数论)
  4. java超时自动关闭_[Java教程]web页面超时自动退出方法_星空网
  5. 区块链与分享型数据库
  6. python 通过ip获取城市_python shell根据ip获取主机名代码示例
  7. Laravel 配置
  8. PMI、砺志咨询活动:项目经理软技能征文大赛—15个PDU、免费软技能培训
  9. 阿里技术面:ReadWriteLock读写之间互斥吗?
  10. Eclipse闪退解决方案
  11. linux zfs raid,ZFS-自我恢复RAID
  12. 动态编程语言静态编程语言_什么是动态编程?
  13. 惠普HP Deskjet D1530 打印机驱动
  14. 通达OA 一个正式用户被提示软件试用过期的问题处理(图文)
  15. python将列表元素全部小写_python实现创建新列表和新字典,并使元素及键值对全部变成小写...
  16. 注册表修复工具+强制卸载工具
  17. 泛微OA-测试机更改sysadmin密码为1
  18. 介绍java糊涂Hutool工具
  19. C++~STL容器实例——三国武将阵营管理系统
  20. 零基础边缘端智慧交通训练营 | Lesson 4

热门文章

  1. fcntl函数之文件锁 F_SETLK
  2. Linux中screen的用法
  3. kafka consumer配置拉取速度慢_Kafka消费者的使用和原理
  4. UVa272-TeX中的引号
  5. (C语言版)栈和队列(二)——实现顺序存储栈和顺序存储队列的相关操作
  6. 【计算机网络实验·北航】实验一:网络实验入门(1)
  7. 7天拿到阿里Android岗位offer,都是精髓!
  8. SQL求一个表中非重复数据及其出现的次数
  9. LINQ to SQL
  10. 浪里个浪 FZU - 2261