马拉车算法

马拉车算法用于寻找字符串中的最长回文子串。

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)

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