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

前端 未结 10 521
走了就别回头了
走了就别回头了 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:18

    I went through the same frustration/struggle and I found the solution on this page, https://www.hackerearth.com/practice/algorithms/string-algorithm/manachars-algorithm/tutorial/, to be easiest to understand. I tried to implement this solution in my own style, and I think I can understand the algorithm now. I also tried to stuff as many explanations in the code as possible to explain the algo. Hope this help!

    #Manacher's Algorithm
    def longestPalindrome(s):
      s = s.lower()
      #Insert special characters, #, between characters
      #Insert another special in the front, $, and at the end, @, of string  to avoid bound checking.
      s1 = '$#'
      for c in s:
          s1 += c + '#'
      s1 = s1+'@'
      #print(s, " -modified into- ", s1)
    
      #Palin[i] = length of longest palindrome start at center i
      Palin = [0]*len(s1)
    
      #THE HARD PART: THE MEAT of the ALGO
    
      #c and r help keeping track of the expanded regions.
      c = r = 0
    
      for i in range(1,len(s1)-1): #NOTE: this algo always expands around center i
    
          #if we already expanded past i, we can retrieve partial info 
          #about this location i, by looking at the mirror from left side of center.
    
          if r > i:  #---nice, we look into memory of the past---
              #look up mirror from left of center c
              mirror = c - (i-c)
    
              #mirror's largest palindrome = Palin[mirror]
    
              #case1: if mirror's largest palindrome expands past r, choose r-i
              #case2: if mirror's largest palindrome is contains within r, choose Palin[mirror]
              Palin[i] = min(r-i, Palin[mirror]) 
    
          #keep expanding around center i
          #NOTE: instead of starting to expand from i-1 and i+1, which is repeated work
          #we start expanding from Palin[i], 
          ##which is, if applicable, updated in previous step
          while s1[i+1+Palin[i]] == s1[i-1-Palin[i]]:
              Palin[i] += 1
    
          #if expanded past r, update r and c
          if i+Palin[i] > r:
              c = i
              r = i + Palin[i]
    
      #the easy part: find the max length, remove special characters, and return
      max_center = max_length = 0
      for i in range(len(s1)):
          if Palin[i] > max_length:
              max_length = Palin[i]
              max_center = i  
      output = s1[max_center-max_length : max_center+max_length]
      output = ''.join(output.split('#'))
      return output # for the (the result substring)
    

提交回复
热议问题