最長回文字符串計算


定義:如果一個字符串正着讀和反着讀是一樣的,那它就是回文串

   例如: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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM