Manacher's algorithm (algorithm to find longest palindrome substring in linear time)

前端 未结 10 524
走了就别回头了
走了就别回头了 2020-12-22 16:02

After spending about 6-8 hours trying to digest the Manacher\'s algorithm, I am ready to throw in the towel. But before I do, here is one last shot in the dark: can anyone e

10条回答
  •  南方客
    南方客 (楼主)
    2020-12-22 16:41

    class Palindrome
    {
        private int center;
        private int radius;
    
        public Palindrome(int center, int radius)
        {
            if (radius < 0 || radius > center)
                throw new Exception("Invalid palindrome.");
    
            this.center = center;
            this.radius = radius;
        }
    
        public int GetMirror(int index)
        {
            int i = 2 * center - index;
    
            if (i < 0)
                return 0;
    
            return i;
        }
    
        public int GetCenter()
        {
            return center;
        }
    
        public int GetLength()
        {
            return 2 * radius;
        }
    
        public int GetRight()
        {
            return center + radius;
        }
    
        public int GetLeft()
        {
            return center - radius;
        }
    
        public void Expand()
        {
            ++radius;
        }
    
        public bool LargerThan(Palindrome other)
        {
            if (other == null)
                return false;
    
            return (radius > other.radius);
        }
    
    }
    
    private static string GetFormatted(string original)
    {
        if (original == null)
            return null;
        else if (original.Length == 0)
            return "";
    
        StringBuilder builder = new StringBuilder("#");
        foreach (char c in original)
        {
            builder.Append(c);
            builder.Append('#');
        }
    
        return builder.ToString();
    }
    
    private static string GetUnFormatted(string formatted)
    {
        if (formatted == null)
            return null;
        else if (formatted.Length == 0)
            return "";
    
        StringBuilder builder = new StringBuilder();
        foreach (char c in formatted)
        {
            if (c != '#')
                builder.Append(c);
        }
    
        return builder.ToString();
    }
    
    public static string FindLargestPalindrome(string str)
    {
        string formatted = GetFormatted(str);
    
        if (formatted == null || formatted.Length == 0)
            return formatted;
    
        int[] radius = new int[formatted.Length];
    
        try
        {
            Palindrome current = new Palindrome(0, 0);
            for (int i = 0; i < formatted.Length; ++i)
            {
                radius[i] = (current.GetRight() > i) ?
                    Math.Min(current.GetRight() - i, radius[current.GetMirror(i)]) : 0;
    
                current = new Palindrome(i, radius[i]);
    
                while (current.GetLeft() - 1 >= 0 && current.GetRight() + 1 < formatted.Length &&
                    formatted[current.GetLeft() - 1] == formatted[current.GetRight() + 1])
                {
                    current.Expand();
                    ++radius[i];
                }
            }
    
            Palindrome largest = new Palindrome(0, 0);
            for (int i = 0; i < radius.Length; ++i)
            {
                current = new Palindrome(i, radius[i]);
                if (current.LargerThan(largest))
                    largest = current;
            }
    
            return GetUnFormatted(formatted.Substring(largest.GetLeft(), largest.GetLength()));
        }
        catch (Exception ex) 
        {
            Console.WriteLine(ex);
        }
    
        return null;
    }
    

提交回复
热议问题