字符串系列之最长回文子串

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

问题描述:

    给定一个字符串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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在中断程序里修改全局变量的童鞋注意啦~(C中的volatile作用 转载~)

一个定义为volatile的变量是说这变量可能会被意想不到地改变&#xff0c;这样&#xff0c;编译器就不会去假设这个变量的值了。精确地说就是&#xff0c;优化器在用到这个变量时必须每次都小心地重新读取这个变量的值&#xff0c;而不是使用保存在寄存器里的备份。下面是volati…

设计模式:单例和简单工厂

单例设计模式&#xff1a;只实例化一个类的对象&#xff01; 1 public class Person2 {3 //1&#xff1a;首先定义一个静态变量4 //2&#xff1a;将该类的构造函数私有化5 //3&#xff1a;定义一个静态方法&#xff0c;将该类对象赋给这个静态变量6 …

python3学习者的福音

偶然发现python3.3.5下的一个非常有用的目录&#xff1a;D:\Embedded\Python33\Lib\lib2to3 这下面的类有详细的说明,关于python2到3所做的一些更改&#xff0c;特别是模块名等&#xff0c;这个非常有用&#xff0c;尤其是对那些参考python2的源码&#xff0c;现在却要用pytho…

powershell 中的pause

一直想在ps中实现cmd中pause的效果 开始用sleep,不理想 无意中试了一下 cmd /c "pause" 可以了 之前一直被“执行会新开一个线程”给误导了 看来可能是调用其它程序时会… ---------------------------------- 备忘&#xff1a; 传枚举值&#xff0c;只要使用枚举值的…

错误:unrecognized command line option “-std=c++11”

From: http://my.oschina.net/chenyoca/blog/226455 摘要出现这个编译错误的原因在g gcc 版本不够高。目录[-] 添加源&#xff08;Ubuntu&#xff09; 安装4.8版本 查看本地安装版本 切换版本 再次查看g版本 出现这个编译错误的原因在g gcc 版本不够高。 添加源&#xff08;Ubu…

Java反射机制深入研究

ava 反射是Java语言的一个很重要的特征&#xff0c;它使得Java具体了“动态性”。在Java运行时环境中&#xff0c;对于任意一个类&#xff0c;能否知道这个类有哪些属性和方法&#xff1f;对于任意一个对象&#xff0c;能否调用它的任意一个方法&#xff1f;答案是肯定的。这种…

编写安全 PHP 应用程序的七个习惯

在提及安全性问题时&#xff0c;需要注意&#xff0c;除了实际的平台和操作系统安全性问题之外&#xff0c;您还需要确保编写安全的应用程序。在编写 PHP 应用程序时&#xff0c;请应用下面的七个习惯以确保应用程序具有最好的安全性&#xff1a; 验证输入保护文件系统保护数据…

linux内核字符设备文件的自动创建

手动创建&#xff1a;mknod自动创建设备文件的步骤&#xff1a;1.保证根文件系统支持mdev可执行程序mdev将来是创建设备文件的真正的人&#xff01;which is mdev //查看mdev的路劲2.保证文件系统的etc目录下有fstab文件&#xff0c;文件内容必须有&#xff1a;proc /proc …

软件工程概论课堂作业3

题目&#xff1a;返回一个整数数组中最大子数组的和 要求&#xff1a; 输入一个一维整形数组&#xff0c;数组里有正数也有负数。 一维数组首尾相接&#xff0c;象个一条首尾相接带子一样。 数组中连续的一个或多个整数组成一个子数组&#xff0c;每个子数组都有一个和。 求所有…

Android硬件访问服务框架思想初识

Android的硬件访问服务提供了一个APP调用硬件实现的方法模型。我们从上往下来看。应用层面对的都是一个个的服务叫service.比如电源管理服务&#xff0c;震动服务等等。应用层代码首先就需要去查询系统是否存在这么一个服务&#xff0c;或者目前是不是可以被获取的。从这个角度…

Ubuntu更新过程被中断后的问题

From: http://defe.me/os/368.html Ubuntu的更新过程是先下载完源里的文件就开始执行升级&#xff0c;如果涉及到一些因为版权或是其他问题没加入源的文件&#xff0c;在升级安装的中途再从第三方服务器上下载。有时需要下载的文件比较大&#xff0c;而网速又不给力&#xff0c…

机器码和字节码

什么是机器码 机器码 机器码(machine code)&#xff0c;学名机器语言指令&#xff0c;有时也被称为原生码&#xff08;Native Code&#xff09;&#xff0c;是电脑的CPU可直接解读的数据。 通常意义上来理解的话&#xff0c;机器码就是计算机可以直接执行&#xff0c;并且执行速…

shell脚本常用语句用法笔记

脚本基本语句用法笔记 grep -i 查询时不区分大小写 -n打印匹配的行号 -v 打印不匹配的行 -AX包括每次匹配之后X行 -BX包括每次匹配之后X行 cat /etc/passwd |grep student (-i 表示不关心大小写) 正则表达式中 ^代表开始 $代表结束 cat /etc/passwd|grep ^# -v (…

CI框架分页类

分页类1.分页类参数说明 base_url > 指向你的分页所在的控制器类/方法的完整的 URL, total_rows > 数据的总行数, per_page > 每页显示的项目, uri_segment > 自动检测哪一段包含页数, num_links > 放在当前页前后显示的链接数, 2.分页类使用 $this->load-&g…

对象运算符.和[]的用法

相同点&#xff1a;它们的第一个运算数都是对象或者数组。 区别&#xff1a;"."将第二个运算数作为对象的属性读写。第二个运算数只能是合法的标识符 "[]"将第二个运算数作为数组的下标来读写。第二个运算数可以是任何类型的值甚至是undefined&#xff0c;…

Linux中对文件描述符的操作(FD_ZERO、FD_SET、FD_CLR、FD_ISSET

在Linux中&#xff0c;内核利用文件描述符&#xff08;File Descriptor&#xff09;即文件句柄&#xff0c;来访问文件。文件描述符是非负整数。打开现存文件或新建文件时&#xff0c;内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。宏FD_ZERO、F…

Host SMBus controller not enabled的解决方法

From: http://blog.csdn.net/starmlk/article/details/7982077 SMBus 目录 SMBus与I2C的差别SMBus 是 System Management Bus 的缩写&#xff0c;是1995年由Intel提出的&#xff0c;应用于移动PC和桌面PC系统中的低速率通讯。它主要是希望通过一条廉价并且功能强大的总线&…

gitlab服务器搭建

搭建教程&#xff1a;http://blog.csdn.net/discoverer100/article/details/51814171#reply

【Bugly干货分享】微信文件微起底Ⅰ

Bugly 技术干货系列内容主要涉及移动开发方向&#xff0c;是由 Bugly 邀请腾讯内部各位技术大咖&#xff0c;通过日常工作经验的总结以及感悟撰写而成&#xff0c;内容均属原创&#xff0c;转载请标明出处 微信大家都在用&#xff0c;但微信的本地文件到底隐藏着什么样的信息呢…