Python-如何找到两个字符串的所有交点?

Python-如何找到两个字符串的所有交点?,python,string,algorithm,Python,String,Algorithm,如何找到两个字符串的所有交点(也称为最长公共子字符串)及其在两个字符串中的位置 例如,如果S1=“从不”和S2=“永远”则结果交点必须是[“永远”],其位置为[(1,3)]。如果S1=“address”和S2=“oddness”则生成的交点是[“dd”,“ess”],它们的位置是[(1,1)、(4,4)] 最好是不包含任何库的最短解决方案。但也欢迎任何正确的解决方案 这可以在O(n+m)中完成,其中n和m是输入字符串的长度 伪代码是: function LCSubstr(S[1..m], T[1

如何找到两个字符串的所有交点(也称为最长公共子字符串)及其在两个字符串中的位置

例如,如果
S1=“从不”
S2=“永远”
则结果交点必须是
[“永远”]
,其位置为
[(1,3)]
。如果
S1=“address”
S2=“oddness”
则生成的交点是
[“dd”,“ess”]
,它们的位置是
[(1,1)、(4,4)]

最好是不包含任何库的最短解决方案。但也欢迎任何正确的解决方案

这可以在O(n+m)中完成,其中
n
m
是输入字符串的长度

伪代码是:

function LCSubstr(S[1..m], T[1..n])
    L := array(1..m, 1..n)
    z := 0
    ret := {}
    for i := 1..m
        for j := 1..n
            if S[i] = T[j]
                if i = 1 or j = 1
                    L[i,j] := 1
                else
                    L[i,j] := L[i-1,j-1] + 1
                if L[i,j] > z
                    z := L[i,j]
                    ret := {}
                if L[i,j] = z
                    ret := ret ∪ {S[i-z+1..z]}
    return ret

有关更多详细信息,请参阅wikipedia文章。

我假设您只希望子字符串在其各自字符串中具有相同的绝对位置时匹配。例如,“abcd”和“bcde”将没有任何匹配项,即使两者都包含“bcd”

位置=
[1,2,4,5,6]

子字符串=
['dd','ess']

如果只需要子字符串,可以将其压缩为一行:

filter(lambda x: x.find("_") == -1 and x != "","".join(map(lambda x: ["_", a[x]][map(lambda x: x[0] == x[1], zip(list(a), list(b)))[x]], range(len(a)))).split("_"))

以下是我能想到的:

import itertools

def longest_common_substring(s1, s2):
   set1 = set(s1[begin:end] for (begin, end) in
              itertools.combinations(range(len(s1)+1), 2))
   set2 = set(s2[begin:end] for (begin, end) in
              itertools.combinations(range(len(s2)+1), 2))
   common = set1.intersection(set2)
   maximal = [com for com in common
              if sum((s.find(com) for s in common)) == -1 * (len(common)-1)]
   return [(s, s1.index(s), s2.index(s)) for s in maximal]
检查某些值:

>>> longest_common_substring('address', 'oddness')
[('dd', 1, 1), ('ess', 4, 4)]
>>> longest_common_substring('never', 'forever')
[('ever', 1, 3)]
>>> longest_common_substring('call', 'wall')
[('all', 1, 1)]
>>> longest_common_substring('abcd1234', '1234abcd')
[('abcd', 0, 4), ('1234', 4, 0)]
包括电池

difflib模块可能会对您有所帮助-下面是一个快速而肮脏的并行diff:

>>> import difflib
>>> list(difflib.ndiff("never","forever"))
['- n', '+ f', '+ o', '+ r', '  e', '  v', '  e', '  r']
>>> diffs = list(difflib.ndiff("never","forever"))
>>> for d in diffs:
...   print {' ': '  ', '-':'', '+':'    '}[d[0]]+d[1:]
...
 n
     f
     o
     r
   e
   v
   e
   r

你是说你不能包括任何图书馆。然而,Python的标准包含了一个函数,它完全满足您的期望。考虑到这是一个Python面试问题,熟悉difflib可能是面试官所期望的

In [31]: import difflib

In [32]: difflib.SequenceMatcher(None, "never", "forever").get_matching_blocks()
Out[32]: [Match(a=1, b=3, size=4), Match(a=5, b=7, size=0)]


In [33]: difflib.SequenceMatcher(None, "address", "oddness").get_matching_blocks()
Out[33]: [Match(a=1, b=1, size=2), Match(a=4, b=4, size=3), Match(a=7, b=7, size=0)]

您始终可以忽略最后一个匹配元组,因为它是虚拟的(根据文档)。

子字符串是否必须在两个字符串中出现在相同的位置(就像在两个示例中一样)?@aix:no,它们可以出现在不同的位置,如“从不”和“永远”。我更改了示例。如果对于
“call”
“wall”
来说,正确的解决方案是
[“all”]
,而不是
[“a”、“al”、“all”、“ll”、“l”]
,那么“所有解决方案”是什么意思?你是说所有的最大解吗?这里的确切定义是什么?你是否关心时间复杂性,或者不太关心时间复杂性?@psihodelia:然后将你的代码作为出发点发布。是的,这是我的第一个想法,但动态编程通常不完全是一行程序。哎呀,在我写答案时,问题似乎变了——OP需要“abcd”和“bcde”匹配,但我开始的时候还不清楚。@agf这就是它返回的结果。。。还是我遗漏了什么?添加了一个测试,该测试显示它返回多个值,并在两个字符串中包含每个子字符串的索引@这就是你想要的吗?啊,我明白了。我错过了“最大”的含义。见更新的答案。宾果。想想时间的复杂性,比如O(n*(n!)+m*(m!)?是的,运行时间非常糟糕,但是对于小字符串来说,它应该工作得很好。谢谢!我认为你的方法是最好的。输出将是ello作为字符串
In [31]: import difflib

In [32]: difflib.SequenceMatcher(None, "never", "forever").get_matching_blocks()
Out[32]: [Match(a=1, b=3, size=4), Match(a=5, b=7, size=0)]


In [33]: difflib.SequenceMatcher(None, "address", "oddness").get_matching_blocks()
Out[33]: [Match(a=1, b=1, size=2), Match(a=4, b=4, size=3), Match(a=7, b=7, size=0)]
def  IntersectStrings( first,  second):
x = list(first)
#print x
y = list(second)
lst1= []
lst2= []
for i in x:
    if i in y:
        lst1.append(i)
lst2 = sorted(lst1) + []
   # This  above step is an optional if it is required to be sorted      alphabetically use this or else remove it
return ''.join(lst2)

print IntersectStrings('hello','mello' )