定義:如果一個字符串正着讀和反着讀是一樣的,那它就是回文串
例如: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