馬拉車算法

馬拉車算法用於尋找字符串中的最長迴文子串。

java

class ManacherAlgo {
    String longestPalindrome(String s) {
        // 填充
        String newS = fillStr(s);

        // center是中心,right是中心的最遠覆蓋範圍,max_center是最長迴文字串的中心
        int right = 0, center = 0, max_center = 0;

        // 記錄每個位置的最遠覆蓋範圍
        int[] radius = new int[newS.length()];
        int lenOfNewS = newS.length();

        // 算法主體
        for (int idx = 1; idx < lenOfNewS; idx++) {
            if (idx < right) {
                int mirror = 2 * center - idx;
                radius[idx] = Math.min(right - idx, radius[mirror]);
            } else
                radius[idx] = 1;

            while (
                    (idx + radius[idx] < lenOfNewS) &&
                            (idx - radius[idx] >= 0) &&
                            (newS.charAt(idx + radius[idx]) == newS.charAt(idx - radius[idx]))
            )
                radius[idx]++;

            if (idx + radius[idx] > right) {
                right = idx + radius[idx];
                center = idx;
            }

            if (radius[idx] > radius[max_center]) {
                max_center = idx;
            }
        }

        // 返回最長迴文字串
        int l = max_center - radius[max_center];
        int r = max_center + radius[max_center];
        return s.substring((l + 1) / 2, r / 2);
    }

    // 填充
    private String fillStr(String s) {
        StringBuilder retS = new StringBuilder("#");
        for (int i = 0; i < s.length(); i++) {
            retS.append(s.charAt(i)).append("#");
        }

        return retS.toString();
    }

    // 測試
    public void testing() {
        System.out.println(longestPalindrome("abababbb"));
        System.out.println(longestPalindrome("aba"));
        System.out.println(longestPalindrome("aa"));
    }
}

public class manacher {

    public static void main(String[] args) {
        // 生成實例
        ManacherAlgo obj = new ManacherAlgo();

        // 測試
        obj.testing();
    }
}

python

# coding=utf-8
"""
author:shayue
2019/09/18
"""


class Manacher():
    """
    算法步驟:
    1. 輸入要操作的字符串後,先進行填充,這一步的目的是爲了無視奇偶差異,填補後的字符串長度必爲奇數;
    2. 從左往右遍歷,以位置center爲中心,往兩邊擴散,記錄最大回文子串的半徑,比如12321,其半徑爲3,將半徑放入列表radius中;
    3. 利用先前已經保存的半徑信息,可以加快後序位置所對應迴文子串的半徑求解,具體實現見longest_palindromic_substring。
    """
    def __init__(self, inputStr):
        self.str_ = inputStr
        self.right = 0
        self.center = 0         #
        self.radius = None      # 列表

        # 下面兩個變量是爲了找到最長子串
        self.MaxPi = 0
        self.Max_Pi_center = 0


    def longest_palindromic_substring(self):
        """
        馬拉車算法,找到最大回文子串並返回
        :return: str
        """
        filled_s = self.fill_to_s()
        self.P = [0] * len(filled_s)
        print(filled_s)

        for idx in range(1, len(filled_s)):
            if idx < self.right:
                mirror = self.get_mirror(idx)
                self.P[idx] = min(self.right - idx, self.P[mirror])
            else:
                self.P[idx] = 1

            while idx - self.P[idx] >= 0 and \
            idx + self.P[idx] < len(filled_s) and \ 
            filled_s[idx - self.P[idx]] == filled_s[idx + self.P[idx]]:
                self.P[idx] += 1

            if self.P[idx] + idx > self.right:
                self.right = self.P[idx] + idx
                self.center = idx

            if self.P[idx] > self.MaxPi:
                self.MaxPi = self.P[idx]
                self.Max_Pi_center = idx

        l = self.Max_Pi_center - self.MaxPi
        r = self.Max_Pi_center + self.MaxPi
        return self.str_[(l+1) // 2: r // 2]

    def get_mirror(self, i):
        """
        以self.center爲中心,返回位置i對應到左邊的位置mirror
        :param i: 位置i,在self.center右邊
        :return: 位置mirror,在self.center左邊
        """
        return 2 * self.center - i

    def fill_to_s(self):
        """
        對self.s進行'#'填充,填充完後的字符串總長爲奇數,以便算法對奇偶情況都適用
        :return: str
        """
        retStr = "#" + "#".join(self.str_) + '#'
        return retStr


if __name__ == '__main__':
    manacher = Manacher('abcababacab')
    print(manacher.longest_palindromic_substring())
    print(manacher.P)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章