【问题标题】:Find the prefix which is also a suffix找到也是后缀的前缀
【发布时间】:2014-05-30 04:48:30
【问题描述】:

我正在寻找这个问题的最佳解决方案。

给定一个string s of length n,找到一个从左到右的前缀,相当于一个从右到左的后缀。

前缀和后缀可以重叠。

示例:给定abababa,前缀为[ababa]ba,后缀为ab[ababa]

我可以做到这一点

  1. 对于每个i = 0 to n-1,取以 i 结尾的前缀并查找是否有合适的后缀。时间是O(n^2)时间和O(1)空间。

  2. 我想出了一个优化,我们可以索引所有字符的位置。这样,我们可以从 1/ 中消除样本空间集。同样,最坏情况的复杂度是 O(n^2)O(n) 额外空间。

有没有更好的算法呢?

【问题讨论】:

  • 查看 Knuth-Morris-Pratt 算法。作为该算法的一部分,您可以使用空间 O(n) 在时间 O(n) 中找到具有此属性的最长边界。
  • 简单的解决方案是返回整个字符串:-)。前任。 ([abababa)]。我猜你想要除了上述值之外的最大可能值?
  • 你能举个例子,其中前缀与其相反的前缀不同吗? - 不清楚前缀和后缀是否都从外部开始(aabxnbaa 中的aab),或者它们是否都从左侧开始(aabxnaab 中的aab,或整个字符串,如 Kevin提到)。
  • 我已经用代码更新了我的答案,看看吧。
  • 谢谢@Danstahr 我会看看。如果可能的话,你能附上关于 KMP needle haystack 的简短描述吗?

标签: string algorithm substring


【解决方案1】:

利用 KMP 算法。算法的状态决定了“大海捞针的最长后缀仍然是针的前缀”。因此,只需将您的字符串作为针,将没有第一个字符的字符串作为干草堆。在O(N) 时间和O(N) 空间中运行。

带有一些示例的实现:

public static int[] create(String needle) {
    int[] backFunc = new int[needle.length() + 1];
    backFunc[0] = backFunc[1] = 0;
    for (int i = 1; i < needle.length(); ++i) {
        int testing = i - 1;
        while (backFunc[testing] != testing) {
            if (needle.charAt(backFunc[testing]) == needle.charAt(i-1)) {
                backFunc[i] = backFunc[testing] + 1;
                break;
            } else {
                testing = backFunc[testing];
            }
        }
    }
    return backFunc;
}

public static int find(String needle, String haystack) {
    // some unused character to ensure that we always return back and never reach the end of the
    // needle
    needle = needle + "$";
    int[] backFunc = create(needle);
    System.out.println(Arrays.toString(backFunc));
    int curpos = 0;
    for (int i = 0; i < haystack.length(); ++i) {
        while (curpos != backFunc[curpos]) {
            if (haystack.charAt(i) == needle.charAt(curpos)) {
                ++curpos;
                break;
            } else {
                curpos = backFunc[curpos];
            }
        }
        if (curpos == 0 && needle.charAt(0) == haystack.charAt(i)) {
            ++curpos;
        }
        System.out.println(curpos);
    }
    return curpos;
}

public static void main(String[] args) {
    String[] tests = {"abababa", "tsttst", "acblahac", "aaaaa"};
    for (String test : tests) {
        System.out.println("Length is : " + find(test, test.substring(1)));
    }
}

【讨论】:

    【解决方案2】:

    C# 中的简单实现:

            string S = "azffffaz";
    
            char[] characters = S.ToCharArray();
            int[] cumulativeCharMatches = new int[characters.Length];
            cumulativeCharMatches[0] = 0;
    
            int prefixIndex = 0;
            int matchCount = 0;
    
            // Use KMP type algorithm to determine matches.
    
            // Search for the 1st character of the prefix occurring in a suffix.
            // If found, assign count of '1' to the equivalent index in a 2nd array.
            // Then, search for the 2nd prefix character.
            // If found, assign a count of '2' to the next index in the 2nd array, and so on.
            // The highest value in the 2nd array is the length of the largest suffix that's also a prefix.
            for (int i = 1; i < characters.Length; i++)
            {
                if (characters[i] == characters[prefixIndex])
                {
                    matchCount += 1;
                    prefixIndex += 1;
                }
                else
                {
                    matchCount = 0;
                    prefixIndex = 0;
                }
    
                cumulativeCharMatches[i] = matchCount;
            }
    
            return cumulativeCharMatches.Max();
    

    【讨论】:

    • 不错的解决方案,但如果你能更好地解释它并且在答案部分而不是仅仅放入 cmets,答案会更好。
    【解决方案3】:

    见:

    http://algorithmsforcontests.blogspot.com/2012/08/borders-of-string.html

    对于 O(n) 解决方案

    代码实际上计算了前缀中最后一个字符的索引。对于实际的前缀/后缀,您需要提取从 0 到 j 的子字符串(都包括在内,长度为 j+1)

    【讨论】:

      猜你喜欢
      • 2019-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 2017-01-23
      相关资源
      最近更新 更多