首先还是先解释一下什么是回文串:就是从左到右或者从右到左读,都是同样的字符串。比如:上海自来水来自海上,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++;// 右边向