最长正确前缀/后缀算法为啥/如何工作?

Posted

技术标签:

【中文标题】最长正确前缀/后缀算法为啥/如何工作?【英文标题】:Why/how does the Longest Proper Prefix/Suffix algorithm work?最长正确前缀/后缀算法为什么/如何工作? 【发布时间】:2020-07-06 06:41:16 【问题描述】:

LPS(Longest Proper Prefix,也是后缀)算法如下:

public static int[] constructLPSArray(String s) 
        int n = s.length();
        int[] arr = new int[n];
        int j = 0;
        for (int i = 1; i < n; ) 
            if (s.charAt(i) == s.charAt(j)) 
                arr[i] = j + 1;
                i++;
                j++;
             else 
                if (j != 0) 
                    j = arr[j - 1];
                 else 
                    i++;
                
            
        
        return arr;
    

if (s.charAt(i) == s.charAt(j)) 部分看起来很清晰,但 else 部分不清楚。 我们为什么这样做:

if (j != 0) 
  j = arr[j - 1];
 else 
  i++;

更具体地说,为什么j = arr[j - 1] 有效?或者我们为什么要这样做?我们如何验证这一步的正确性?

【问题讨论】:

【参考方案1】:

假设我们正在解析一个字符数组,其中 ij 的位置如下:

a b a b x x a b a b ...
      ^           ^
      j           i

arr 持有:

0 0 1 2 0 0 1 2 3 4

我。例如,该长度的 s 的每个子串的最长前缀/后缀的长度,直到i。您可能会猜到它是如何从算法的其余部分生成的。现在,如果i 之后的下一个字符与j 之后的下一个字符不匹配,

a b a b x x a b a b a ...
        ^           ^
        j           i

我们不必重试匹配,因为我们知道最长的前缀/后缀我们之前的前缀/后缀!查找 arr[j - 1] 得到 2 - 所以我们基本上缓存了此处突出显示的部分的信息

A B a b x x a b A B a ...
=== ^           === ^
    j               i

完全相同,无需再比较!

【讨论】:

你能解释一下为什么时间复杂度是 O(n) 而不是 n^2 其中 n 是字符串的长度吗?由于 'j' 可能会在某些循环迭代中递减,它似乎可能是 O(n^2) 它是否需要查找“我们之前的前缀/后缀的最长前缀/后缀”,它只为任何 i 递减一次 j?想知道它的复杂性如何是线性的。 @JoeBlack x = # i,j 增加; y = # j 减少; z = # 只有 i 增加了; A = x+y+z = 我们知道 x+z 【参考方案2】:
  *Here's one more solution*
  int length=str.length();
  int mid=length/2;
  if(length<2)
       System.out.println("-1");
  
  for(int i=mid;i>=0;i--)
      String prefix=str.substring(0,i);
      String suffix=str.substring(length-i,length);
      if(suffix.equals("") || prefix.equals(""))
            System.out.println("-1");
      
      if(suffix.equals(prefix))
          System.out.println(suffix.length());
          break;
      
      
  
  

【讨论】:

以上是关于最长正确前缀/后缀算法为啥/如何工作?的主要内容,如果未能解决你的问题,请参考以下文章

算法学习:后缀数组 height的求取

KMP算法

KMP算法

扩展KMP算法

如何在rust中迭代str或String的前缀和后缀?

为啥将迭代器作为参数传递并在尾部位置递归时后缀失败并且前缀工作正常? [复制]