我有一个很长的字符串。我想找到这个字符串的所有唯一子串。我尝试编写代码,我使用 set (python)存储所有子字符串以确保唯一性。我得到了许多中大字符串的正确结果,但是如果字符串很大,我会得到一个MemoryError。我google了一下,发现python中的 set 数据结构有一个很大的RAM占用空间,这也许就是我得到MemoryError的原因。
这是我的代码:
a = set()
for i in range(n):
string = raw_input()
j = 1
while True:
for i in xrange(len(string)-j+1):
a.add(string[i:i+j])
if j==len(string): break
j+=1
print sorted(list(a))
有没有办法避免大字符串的这个错误?或者任何人都可以在我的代码中建议更好的修改来处理这个问题?
P.S:我没有选择在32位和64位版本之间转换。
答案 0 :(得分:4)
如果你真的需要它在内存中,那么你可以尝试制作一个后缀树。尝试不是外来数据结构,因此可能有很好的实现可用于主流语言,如Python,它们可用于实现后缀树。 Marisa-Trie应该可以获得良好的内存使用率。
答案 1 :(得分:0)
这是一些基于O(n)后缀树结构的Python代码,用于从输入字符串集合中生成唯一的子字符串(输出应按排序顺序显示,因此之后无需对字符串进行排序)。 / p>
由于可能有O(n ^ 2)个输出字符串,实际输出所有字符串可能需要很长时间。
from collections import defaultdict
class SuffixTree:
def __init__(self):
"""Returns an empty suffix tree"""
self.T=''
self.E={}
self.nodes=[-1]
def add(self,s):
"""Adds the input string to the suffix tree.
This inserts all substrings into the tree.
End the string with a unique character if you want a leaf-node for every suffix.
Produces an edge graph keyed by (node,character) that gives (first,last,end)
This means that the edge has characters from T[first:last+1] and goes to node end."""
origin,first,last = 0,len(self.T),len(self.T)-1
self.T+=s
nc = len(self.nodes)
self.nodes += [-1]*(2*len(s))
T=self.T
E=self.E
nodes=self.nodes
Lm1=len(T)-1
for last_char_index in xrange(first,len(T)):
c=T[last_char_index]
last_parent_node = -1
while 1:
parent_node = origin
if first>last:
if (origin,c) in E:
break
else:
key = origin,T[first]
edge_first, edge_last, edge_end = E[key]
span = last - first
A = edge_first+span
m = T[A+1]
if m==c:
break
E[key] = (edge_first, A, nc)
nodes[nc] = origin
E[nc,m] = (A+1,edge_last,edge_end)
parent_node = nc
nc+=1
E[parent_node,c] = (last_char_index, Lm1, nc)
nc+=1
if last_parent_node>0:
nodes[last_parent_node] = parent_node
last_parent_node = parent_node
if origin==0:
first+=1
else:
origin = nodes[origin]
if first <= last:
edge_first,edge_last,edge_end=E[origin,T[first]]
span = edge_last-edge_first
while span <= last - first:
first+=span+1
origin = edge_end
if first <= last:
edge_first,edge_last,edge_end = E[origin,T[first]]
span = edge_last - edge_first
if last_parent_node>0:
nodes[last_parent_node] = parent_node
last+=1
if first <= last:
edge_first,edge_last,edge_end=E[origin,T[first]]
span = edge_last-edge_first
while span <= last - first:
first+=span+1
origin = edge_end
if first <= last:
edge_first,edge_last,edge_end = E[origin,T[first]]
span = edge_last - edge_first
return self
def make_choices(self):
"""Construct a sorted list for each node of the possible continuing characters"""
choices = self.choices = [list() for n in xrange(len(self.nodes))] # Contains set of choices for each node
for (origin,c),edge in self.E.items():
choices[origin].append(c)
choices=[sorted(s) for s in choices] # should not have any repeats by construction
return choices
def find_substrings(self,A,term):
"""Recurses through the tree appending unique substrings into A.
Strings assumed to use term as the terminating character"""
choices = self.make_choices()
def f(node,depth):
t=0
for c in choices[node]:
if c==term: continue
first,last,end = self.E[node,c]
# All end points along this edge result in new unique substrings
edge_len = last-first+1
a = first-depth
for b in range(first,last+1):
if self.T[b]!=term:
A.append( self.T[a:b+1] )
f(end,depth+edge_len)
return t
return f(0,0)
def fast_find_all_substrings(strings):
S = SuffixTree()
term = '\0'
for string in strings:
S.add(string+term)
A=[]
S.find_substrings(A,term)
return A
A="abc","abcd","bca"
print fast_find_all_substrings(A)