两个以上字符串中最长的公共子字符串-Python
我正在寻找一个Python库,用于从一组字符串中查找最长的公共子字符串。有两种方法可以解决此问题:两个以上字符串中最长的公共子字符串-Python,python,string,longest-substring,Python,String,Longest Substring,我正在寻找一个Python库,用于从一组字符串中查找最长的公共子字符串。有两种方法可以解决此问题: 使用后缀树 使用动态规划 实现的方法并不重要。重要的是,它可以用于一组字符串(而不仅仅是两个字符串)。def common_前缀(字符串): “”“查找作为所有字符串前缀的最长字符串。 """ 如果不是字符串: 返回“” 前缀=字符串[0] 对于字符串中的s: 如果len(s)len(substr)并且是任意(数据[0][i:i+j],数据)的子对象: substr=数据[0][i:i+j]
- 使用后缀树
- 使用动态规划
def common_前缀(字符串):
“”“查找作为所有字符串前缀的最长字符串。
"""
如果不是字符串:
返回“”
前缀=字符串[0]
对于字符串中的s:
如果len(s)
从中,这些成对函数将在任意字符串数组中找到最长的公共字符串:
def long_substr(data):
substr = ''
if len(data) > 1 and len(data[0]) > 0:
for i in range(len(data[0])):
for j in range(len(data[0])-i+1):
if j > len(substr) and is_substr(data[0][i:i+j], data):
substr = data[0][i:i+j]
return substr
def is_substr(find, data):
if len(data) < 1 and len(find) < 1:
return False
for i in range(len(data)):
if find not in data[i]:
return False
return True
print long_substr(['Oh, hello, my friend.',
'I prefer Jelly Belly beans.',
'When hell freezes over!'])
希望这有帮助
杰森
免责声明这对雅克的回答没有什么补充。然而,希望这应该更容易阅读,速度更快,并且它不适合评论,因此我在回答中发布了这篇文章。老实说,我对
中最短的不满意。您可以使用后缀树模块,它是基于泛化后缀树的ANSI C实现的包装器。该模块易于处理
请看:我更喜欢这一点,因为我觉得它更具可读性和直观性:
def is_substr(find, data):
"""
inputs a substring to find, returns True only
if found for each data in data list
"""
if len(find) < 1 or len(data) < 1:
return False # expected input DNE
is_found = True # and-ing to False anywhere in data will return False
for i in data:
print "Looking for substring %s in %s..." % (find, i)
is_found = is_found and find in i
return is_found
def是_substr(查找,数据):
"""
输入要查找的子字符串,仅返回True
如果为数据列表中的每个数据找到
"""
如果len(find)<1或len(data)<1:
返回False#预期输入DNE
is_found=True#如果在数据中的任何位置将其设置为False,则返回False
对于数据中的i:
打印“查找%s中的子字符串%s…”%(查找,i)
is_found=is_found and find in i
已找到退货
如果有人正在寻找一个通用版本,该版本还可以获取任意对象序列的列表:
def get_longest_common_subseq(data):
substr = []
if len(data) > 1 and len(data[0]) > 0:
for i in range(len(data[0])):
for j in range(len(data[0])-i+1):
if j > len(substr) and is_subseq_of_any(data[0][i:i+j], data):
substr = data[0][i:i+j]
return substr
def is_subseq_of_any(find, data):
if len(data) < 1 and len(find) < 1:
return False
for i in range(len(data)):
if not is_subseq(find, data[i]):
return False
return True
# Will also return True if possible_subseq == seq.
def is_subseq(possible_subseq, seq):
if len(possible_subseq) > len(seq):
return False
def get_length_n_slices(n):
for i in xrange(len(seq) + 1 - n):
yield seq[i:i+n]
for slyce in get_length_n_slices(len(possible_subseq)):
if slyce == possible_subseq:
return True
return False
print get_longest_common_subseq([[1, 2, 3, 4, 5], [2, 3, 4, 5, 6]])
print get_longest_common_subseq(['Oh, hello, my friend.',
'I prefer Jelly Belly beans.',
'When hell freezes over!'])
def get_longest_common_subseq(数据):
substr=[]
如果len(数据)>1且len(数据[0])>0:
对于范围内的i(len(数据[0]):
对于范围内的j(len(数据[0])-i+1):
如果j>len(substr)并且是任意(数据[0][i:i+j],数据)的子对象:
substr=数据[0][i:i+j]
返回子序列
def是任何(查找、数据)的子项:
如果len(数据)<1且len(查找)<1:
返回错误
对于范围内的i(len(数据)):
如果不是,则为第Q子部分(查找,数据[i]):
返回错误
返回真值
#如果可能,也将返回True\u subseq==seq。
def为子部分(可能的子部分,顺序):
如果len(可能)>len(序号):
返回错误
def get_长度_n_切片(n):
对于x范围内的i(len(seq)+1-n):
收益率序列[i:i+n]
对于获取长度n个切片中的slyce(len(可能的子集)):
如果slyce==可能的子问题:
返回真值
返回错误
打印获取最长公共子Q([[1,2,3,4,5],[2,3,4,5,6])
打印获取最长的公共子标题([“哦,你好,我的朋友。”),
“我更喜欢果冻肚豆。”,
“当地狱结冰时!”)
这可以缩短时间:
def long_substr(数据):
substrs=lambda x:{x[i:i+j]表示范围内的i(len(x))表示范围内的j(len(x)-i+1)}
s=SUBSTR(数据[0])
对于数据[1:]中的val:
s、 交叉口_更新(SUBSTR(val))
返回最大值(s,key=len)
集合(可能)被实现为散列映射,这使得这有点低效。如果您(1)实现一个集数据类型作为一个trie,并且(2)只将后缀存储在trie中,然后强制每个节点成为一个端点(这相当于添加所有子字符串),那么从理论上讲,我猜这个婴儿相当节省内存,特别是因为尝试的交叉非常容易
然而,这是短暂的,过早的优化是浪费大量时间的根源。我的回答很慢,但很容易理解。处理一个包含100个1KB字符串的文件大约需要两秒钟,如果有多个子字符串,则返回任意一个最长的子字符串
ls = list()
ls.sort(key=len)
s1 = ls.pop(0)
maxl = len(s1)
#1创建按长度向后排序的所有子字符串的列表。因此,我们不必检查整个列表
subs = [s1[i:j] for i in range(maxl) for j in range(maxl,i,-1)]
subs.sort(key=len, reverse=True)
#2检查一个子串是否下一个最短,然后下一个等。如果不在任何下一个最短的字符串中,则中断循环,这是不常见的。如果它通过了所有检查,那么默认情况下它是最长的一个,打破循环
def isasub(subs, ls):
for sub in subs:
for st in ls:
if sub not in st:
break
else:
return sub
break
print('the longest common substring is: ',isasub(subs,ls))
Caveman解决方案,它将根据作为列表传递的子字符串长度,为您提供一个具有字符串中最频繁子字符串的数据帧:
import pandas as pd
lista = ['How much wood would a woodchuck',' chuck if a woodchuck could chuck wood?']
string = ''
for i in lista:
string = string + ' ' + str(i)
string = string.lower()
characters_you_would_like_to_remove_from_string = [' ','-','_']
for i in charecters_you_would_like_to_remove_from_string:
string = string.replace(i,'')
substring_length_you_want_to_check = [3,4,5,6,7,8]
results_list = []
for string_length in substring_length_you_want_to_check:
for i in range(len(string)):
checking_str = string[i:i+string_length]
if len(checking_str) == string_length:
number_of_times_appears = (len(string) - len(string.replace(checking_str,'')))/string_length
results_list = results_list+[[checking_str,number_of_times_appears]]
df = pd.DataFrame(data=results_list,columns=['string','freq'])
df['freq'] = df['freq'].astype('int64')
df = df.drop_duplicates()
df = df.sort_values(by='freq',ascending=False)
display(df[:10])
结果是:
string freq
78 huck 4
63 wood 4
77 chuc 4
132 chuck 4
8 ood 4
7 woo 4
21 chu 4
23 uck 4
22 huc 4
20 dch 3
您的算法具有O(n1*n1*(n1+…+nK))时间复杂度,但使用后缀树可以将其降低为Θ(n1+…+nK)是Θcommon_substr=lambda s,strings:all(x中的s表示字符串中的x)
对于具有单个元素的列表,它返回空字符串。在这种情况下,返回元素本身可能更有意义。应该提到的是,如果有多个相同长度的匹配序列,则只查找第一个最长的公共子字符串,而不是全部。尝试例如,.[Los Angeles”,“Lossless']由@J.F.Sebastian提出的添加是否提高了时间复杂度?请检查shortest\u of
的“functional”版本。如果最长公共子字符串位于引用字符串的末尾,则会遗漏其最后一个字符。可以通过将xrange(i+len(substr)+1,长度)中j的替换为xrange(i+len(substr)+1,长度+1)中j的,
来修复此问题。链接已断开,您没有进行任何描述或示例
def isasub(subs, ls):
for sub in subs:
for st in ls:
if sub not in st:
break
else:
return sub
break
print('the longest common substring is: ',isasub(subs,ls))
import pandas as pd
lista = ['How much wood would a woodchuck',' chuck if a woodchuck could chuck wood?']
string = ''
for i in lista:
string = string + ' ' + str(i)
string = string.lower()
characters_you_would_like_to_remove_from_string = [' ','-','_']
for i in charecters_you_would_like_to_remove_from_string:
string = string.replace(i,'')
substring_length_you_want_to_check = [3,4,5,6,7,8]
results_list = []
for string_length in substring_length_you_want_to_check:
for i in range(len(string)):
checking_str = string[i:i+string_length]
if len(checking_str) == string_length:
number_of_times_appears = (len(string) - len(string.replace(checking_str,'')))/string_length
results_list = results_list+[[checking_str,number_of_times_appears]]
df = pd.DataFrame(data=results_list,columns=['string','freq'])
df['freq'] = df['freq'].astype('int64')
df = df.drop_duplicates()
df = df.sort_values(by='freq',ascending=False)
display(df[:10])
string freq
78 huck 4
63 wood 4
77 chuc 4
132 chuck 4
8 ood 4
7 woo 4
21 chu 4
23 uck 4
22 huc 4
20 dch 3