C语言 c++ php mysql nginx linux lnmp lamp lanmp memcache redis 面试 笔记 ppt 设计模式 问题 远程连接

最长回文字符串计算

定义:如果一个字符串正着读和反着读是一样的,那它就是回文串

   例如:aba 、 abba 不限制奇数偶数

判断是否是回文字符串

  思路:从最前后各去一个做对比,如果相同则进行下一个,直到相挨为止

function palindrome($str) {

    $i = 0;
    $j = strlen($str)-1;

    $flag = 1;

    while($i<$j)
    {

        if($str[$i] != $str[$j])
        {
            $flag = 0;
            break;
        }

        $i++;
        $j--;

    }
    
    return $flag;
    
}

 

计算最长回文字串

方法1:

  暴力破解:计算出每个可能的字串,然后对比   

  时间复杂度:n(n^3)

function findLongestPalindrome($str)
{
    $palindrome = array();
    
    for($i=0;$i<strlen($str);$i++)
    {
        for($j=$i+1;$j<strlen($str);$j++)
        {
            $sub = substr($str, $i, $j-$i+1);
            if(palindrome($sub))
            {
                $palindrome[] = strlen($sub);
            }
        }
    }
    
    return $palindrome ? max($palindrome) : 0;
    
}

 

方法2:中心扩展

中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)。
但是要考虑两种情况:
1、像aba,这样长度为奇数。
2、想abba,这样长度为偶数。

function findLongestPalindrome($str)
{
    $maxLen = 0;
    
    for($i=0;$i<strlen($str);$i++)
    {
        //奇数需要减1
        $left  = $i-(strlen($str)%2 == 0 ? 0 : 1);//左边走
        $right = $i+1;//右边走
        
        while($left>=0 && $right<strlen($str) && $str[$left] == $str[$right])
        {
            if($right-$left+1>$maxLen)
            {
                $maxLen = $right-$left+1;
            }
            
            $left --;
            $right ++;
            
        }
    }
    
    return $maxLen;
    
}

 

方法3:Manacher

  1、奇偶数的问题,在字符串两边和中间分别插入特殊符号(如:#) 后,没个字符串都为奇数(奇数+偶数=奇数)

  2、重复访问问题,根据回文字符串的对称性快速扩展回文串

function findLongestPalindrome($str)
{
    //预处理,字符中间和两边增加#字符
    $strArr = str_split($str);    
    $str = '#'.implode('#', $strArr).'#';
    
    $maxLen = 0;
    
    $rl = array();//记录以该字符为中心的最长回文字符串半径
    $maxRight = 0;//现在访问到的最右边的字符
    $pos = 0; //$maxRight位置对应的轴位置
    
    for($i=0;$i<strlen($str);$i++)
    {
        if($i<$maxRight) //在左边
        {
            //根据回文串的对称性得出
            //应该为$pos-($pos-$i)],但最大不能超过 $maxRight-1 
            $rl[$i] = min($rl[$pos-($i-$pos)], $maxRight-1);
        }else{
            $rl[$i] = 1;
        }
        
        //向两边扩展 两边不能越界,且新的两边的字符还必须相等
        while($i-$rl[$i]>=0 && $i+$rl[$i]<strlen($str) && ($str[$i-$rl[$i]] == $str[$i+$rl[$i]]))
        {
            $rl[$i]++;
            
        }
        
        //更新 maxright,pos
        if($i+$rl[$i]-1>$maxRight)
        {
            $maxRight = $i+$rl[$i]-1;
            $pos = $i;
        }
        
        $maxLen = max($maxLen, $rl[$i]);
    }
    
    return $maxLen - 1;
}

 

参考:http://www.cnblogs.com/leoin2012/p/3984997.html

    https://segmentfault.com/a/1190000003914228

 

posted on 2017-02-28 23:38  思齐_  阅读(4641)  评论(0编辑  收藏  举报