更有效的子串计算方法

时间:2016-02-16 17:47:46

标签: python algorithm

我的代码有效,我正在寻找更聪明的想法以提高效率?

对于字符串相似性,它被定义为最长公共前缀长度, 例如,“abc”和“abd”为2,“aaa”和“aaab”为3。

问题是计算字符串S及其所有后缀的相似性, 将自己包括为第一个后缀。

例如,对于S =“ababaa”,后缀是“ababaa”,“babaa”,“abaa”,“baa”,“aa” 和“a”,相似度为6 + 0 + 3 + 0 + 1 + 1 = 11

# Complete the function below.
from collections import defaultdict

class TrieNode:
    def __init__(self):
        self.children=defaultdict(TrieNode)
        self.isEnd=False
class TrieTree:
    def __init__(self):
        self.root=TrieNode()
    def insert(self, word):
        node = self.root
        for w in word:
            node = node.children[w]
        node.isEnd = True
    def search(self, word):
        node = self.root
        count = 0
        for w in word:
            node = node.children.get(w)
            if not node:
                break
            else:
                count += 1
        return count

def  StringSimilarity(inputs):
    resultFormat=[]
    for word in inputs:
        # build Trie tree
        index = TrieTree()
        index.insert(word)
        result = 0
        # search for suffix
        for i in range(len(word)):
            result += index.search(word[i:])
        print result
        resultFormat.append(result)

    return resultFormat

3 个答案:

答案 0 :(得分:2)

def similarity(s, t):
    """ assumes len(t) <= len(s), which is easily doable"""
    i = 0
    while i < len(t) and s[i] == t[i]:
        i += 1
    return i

def selfSimilarity(s):
    return sum(similarity(s, s[i:]) for i in range(len(s)))

selfSimilarity("ababaa")
# 11

答案 1 :(得分:1)

构建TrieTree对象需要做很多工作。跳过那个。只需对匹配的所有可能起点进行双循环,以及可能仍然匹配的所有可能偏移。

如果您要多次查询数据结构,那么构建这样的复杂对象才有意义。但是你不是这样,它不会得到回报。

答案 2 :(得分:1)

以下是您可能希望考虑的3种有效方法:

后缀树

计算原始字符串的后缀树。然后通过后缀树下降主路径,计算每个阶段离开校长的路径数。

后缀数组

计算后缀数组和最长公共前缀数组。 这些数组可用于计算任何一对足够的最长前缀,特别是原始字符串和每个后缀之间的最长前缀。

Z功能

您尝试构建的输出称为Z功能。 它可以直接在线性时间内计算,如here所示(显然不是Python代码):

vector z_function(string s) {
    int n = (int) s.length();
    vector z(n);
    for (int i = 1, l = 0, r = 0; i < n; ++i) {
        if (i <= r)
            z[i] = min (r - i + 1, z[i - l]);
        while (i + z[i] < n && s[z[i]] == s[i + z[i]])
            ++z[i];
        if (i + z[i] - 1 > r)
            l = i, r = i + z[i] - 1;
    }
    return z;
}