php算法题:最长回文子串

ahxxx 2019-11-03

5:最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

一、法一暴力破解

这个就不用多解释了

class Solution {

    /**
     * 法一:
     * @param String $s
     * @return String
     */
    function longestPalindrome($s) {
        $len = strlen($s);
        $tmps = '';
        $max = 0;
        for($i=0 ; $i<$len; $i++){ //起始下标
            for($j=$i+1; $j<=$len;$j++){ //长度
                if($this->isPalindrome(substr($s,$i,$j)) && $j > $max){
                    $tmps = substr($s,$i,$j);
                    $max = $j;
                }
            }
        }
        return $tmps;
    }

    function isPalindrome($subs){
        $len = strlen($subs);
        for($i=0; $i<(int)($len/2); $i++){
            if($subs[$i] != $subs[$len-$i-1]){
                return false;
            }
        }
        return true;
    }
}

二、最长公共子串

思路:就是把字符串反转过来,例如 s=‘ababc’,反正s‘=’cbaba‘,两个字符串左右重合,得出最长的子串就是答案,也就是bab(或aba)。但是有可能会出现==特例(如:S = abc435cba,S' = abc534cba)==,重合,子串为abc。不符合条件,需要加判断

class Solution2 {

    /**
     * @param String $s
     * @return String
     */
    function longestPalindrome($s) {
        $len = strlen($s);
        if($len == ''){
            return $s;
        }
        $origin = $s;
        $reverse = strrev($s);
        $arr = [];
        $maxLen = 0;
        $maxStart = 0;

        for($i=0; $i<$len; $i++){//原始字符串下标
            for($j=0; $j<$len; $j++){ //倒置后字符串下标
                if($origin[$i] == $reverse[$j]){
                    if($i == 0 || $j ==0){
                        $arr[$i][$j] = 1;
                    }else{
                        //状态转移方程
                        $arr[$i][$j] = $arr[$i-1][$j-1] + 1;
                    }
                    /**
                     * 用来规避特殊情况
                     * 如:S = abc435cba,S' = abc534cba
                     * 不特殊处理,abc 会被判断为最小回文子串
                     * 解:判断倒置前的子串下标,是否符合条件
                     */
                    if($arr[$i][$j] > $maxLen){
                        $beforeJ = $len - $j - 1;
                        if($beforeJ + $arr[$i][$j] -1 == $i){
                            $maxLen = $arr[$i][$j];
                            $maxStart = $i;
                        }
                    }
                }else{
                    $arr[$i][$j] = 0;
                }
            }
        }
        echo substr($s,$maxStart-$maxLen+1,$maxLen);
    }
}

三、中心拓展法

把每个字母当成回文串的中心。考虑两种情况,长度为奇数和偶数

class Solution3 {

    /**
     * @param String $s
     * @return String
     */
    function longestPalindrome($s) {
        $n = strlen($s);
        if($n == ''){
            return $s;
        }
        $start = 0;
        $maxlen = 0;

        for($i=0; $i<$n; $i++){
            $len1 = $this->isPalindrome($s,$i,$i);//奇数
            $len2 = $this->isPalindrome($s,$i,$i+1);//偶数
            $len = max($len1,$len2);
            if($len > $maxlen){
                $start = $i - ($len-1)/2;
                $maxlen = $len;
            }
        }
        return substr($s,$start,$len) ;
    }

    function expend($str,$i,$j){
        $n = strlen($str);
        $l = $i;
        $r = $j;

        while($l>=0 && $r<$n && $str[$l] == $str[$r]){
            $l-- ;
            $r++ ;
        }

        return $r-$l-1;

    }
}

三、马拉车算法

重新组合字符串,将其变为奇数个。充分的利用回文串的对称性质,

class Solution4 {

    /**
     * @param String $s
     * @return String
     */
    function longestPalindrome($s) {
        $T = $this->malache($s);
        $n = strlen($T);
        $C = $R = 0;
        $p = [];
        for($i=1; $i<$n-1; $i++){
            $i_mirror = $C*2 - $i;
            if($R>$i){
                $p[$i] = min($R-$i,$p[$i_mirror]);
            }else{
                $p[$i] = 0;
            }
            while(($T[$i-1-$p[$i]]) == ($T[$i+1+$p[$i]]) ){
                $p[$i]++;
            }
            if($i + $p[$i] > $R) {
                $C = $i;
                $R = $i + $p[$i];
            }
        }
        $maxLen = 0;
        $centerIndex = 0;
        for ($i=1; $i<$n-1;$i++ ){
            if($p[$i] > $maxLen){
                $maxLen = $p[$i];
                $centerIndex = $i;
            }
        }

        $start = ($centerIndex-$maxLen)/2;
        echo substr($s,$start,$maxLen);
    }

    function malache($str){
        $n = strlen($str);
        if(!$str){
            return "^$";
        }
        $ret = '^';

        for($i=0; $i<$n; $i++){
            $ret .= '#'.$str[$i];
        }
        $ret .= "#$";

        return $ret;

    }
}

相关推荐