首页 > 技术文章 > 最长(大)回文串的查找(字符串中找出最长的回文串)PHP实现

leafinwind 2019-02-26 23:56 原文

首先还是先解释一下什么是回文串:就是从左到右或者从右到左读,都是同样的字符串。比如:上海自来水来自海上,bob等等。

那么什么又是找出最长回文串呢?

例如:字符串abcdefedcfggggggfc,其中efe,defed,cdefedc,gg,ggg,gggg,ggggg,gggggg,fggggggf,cfggggggfc都是回文串,左右完全一样。

这其中,有最短的gg,最长的cfggggggfc,还有其他长度的。忽略长度为1的。毕竟一个字符的都算回文了。

那么,找出最长的,就是找出这个cfggggggfc。

说实话,最开始想到的办法,就是暴力的枚举,也就是找出原字符串的所有子串,然后逐一判断是否是回文串,如果是就记录下来该字符串。

然后,碰到下一个回文串的时候,再对比两个字符串的长度,谁长,就把谁记录下来。

感觉遍历、枚举这类操作真的是万能的。。。

 

先来段暴力的代码,定个场。

通过两层循环,逐一筛选字符串的子串,找出所有回文串,并不断判断,记录最长的回文串

 1 function is_palindrome($str)
 2 {
 3     $strrev = strrev($str);// 逆序字符串
 4     return $strrev == $str ? 1 : 0;
 5 }
 6 
 7 function get_max_palindrome($str)
 8 {
 9     $len = strlen($str);
10     $res = '';// 结果
11     for ($i = 0; $i < $len - 2; $i++) {// $i 用于定义字符串起始位置,倒数第二个和最后一个如果还不能组成回文串,最后一个就不需要截取了
12         for ($j = $i + 2; $j <= $len; $j++) {// $j 用于逐一延长子字符串的长度,($j=$i+2)截取子串长度2位起,所以循环条件使用的是<=不是<
13             $tmp = substr($str, $i, $j - $i);// 逐一截取子串
14             if (is_palindrome($tmp)) {// 判断当前截取的子串是否是回文串
15                 if (strlen($tmp) > strlen($res)) {// 是回文串,则再判断是否长度大于结果中保存的回文串
16                     $res = $tmp;// 当前回文串大于结果中的,将结果变量更新成当前的回文串
17                 }
18             }
19         }
20     }
21     return $res;
22 }
23 
24 $str = "abcdefedcfggggggfc";
25 echo get_max_palindrome($str);

这方法感觉还不错,简单直观,并且代码也算简单。就是会被鄙视,毕竟这个太初级,太暴力。越简单粗暴不是越好么?

 

简单粗暴的有了,有没有可以装一下的?有没有什么好玩的?有没有......于是就有了下边的程序。

 1 function get_max_palindrome1($str)
 2 {
 3     $len = strlen($str);
 4     $res = [];// 结果数组
 5     $res2= [];// 偶数长度的结果
 6     // 使用array_unshift的目的是为了从前向数组插入每一次找到的答案。也可以直接更新单个元素数组,就是只要当前取到的字符串比原来的长,就把原来的覆盖掉
 7     // 使用多维数组不是必须的,以为数组或者变量也可以。这里就是做一个简单的记录,可以微调一下,多完成另一个功能
 8     array_unshift($res, $str[0]);// 默认将第一个字符作为最长回文串写入数组
 9     array_unshift($res2, '');// 默认一个空字符串,长度为0,初始化
10 
11     for ($i = 1; $i < $len - 1; $i++) {// 从第二个开始操作,因为第一个左边没有字符,只能算本身长度为1的回文串
12         // 针对奇数长度的最长回文串
13         $left = $right = $i;// 从中间向两边扩展,默认起始位置为中间的这个位置
14         $tmp = $str[$i];// 临时回文串,用于中间数据处理,默认是当前字符串
15         while ($left > 0 and $right < $len - 1) {// 限定,只要有任何一边到头,循环结束
16             $left--;// 左边向左扩展
17             $right++;// 右边向

推荐阅读