如何找到两个字符串中的两个字符串及其位置的所有交叉点(也称为最长公共子字符串)?
例如,如果S1="never"
和S2="forever"
,则结果必须为["ever"]
且其位置为[(1,3)]
。如果S1="address"
和S2="oddness"
导致交叉点为["dd","ess"]
且其位置为[(1,1),(4,4)]
。
最好的解决方案,不包括任何库是可取的。但欢迎任何正确的解决方案。
答案 0 :(得分:12)
嗯,你说你不能包括任何图书馆。但是,Python的标准difflib包含一个完全符合您期望的函数。考虑到这是一个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)]
你总是可以忽略最后一个Match元组,因为它是虚拟的(根据文档)。
答案 1 :(得分:7)
这可以在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
有关详细信息,请参阅Longest_common_substring_problem维基百科文章。
答案 2 :(得分:5)
这是我能想到的:
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)]
答案 3 :(得分:4)
包括电池!
difflib模块可能对你有所帮助 - 这是一个快速而又肮脏的并排差异:
>>> 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
答案 4 :(得分:1)
我假设您只希望子串匹配,如果它们在各自的字符串中具有相同的绝对位置。例如,“abcd”和“bcde”将不会有任何匹配,即使两者都包含“bcd”。
a = "address"
b = "oddness"
#matches[x] is True if a[x] == b[x]
matches = map(lambda x: x[0] == x[1], zip(list(a), list(b)))
positions = filter(lambda x: matches[x], range(len(a)))
substrings = filter(lambda x: x.find("_") == -1 and x != "","".join(map(lambda x: ["_", a[x]][matches[x]], range(len(a)))).split("_"))
positions = [1, 2, 4, 5, 6]
substrings = ['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("_"))
答案 5 :(得分: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' )