파이썬 2, 646 바이트
G=range;w=raw_input;z=L,m,h=[0]*3
s=w();t=len(s);s+='!%s#'%w();u=len(s);I=z*u
def f(s,n):
def r(o):
b=[[]for _ in s];c=[]
for x in B[:N]:b[s[x+o]]+=x,
map(c.extend,b);B[:N]=c
M=N=n--~n/3;t=n%3%2;B=G(n+t);del B[::3];r(2);u=m=p=r(1)>r(0);N-=n/3
for x in B*1:v=s[x:x+3];m+=u<v;u=v;B[x/3+x%3/2*N]=m
A=1/M*z or f(B+z,M)+z;B=[x*3for x in A if x<N];J=I[r(0):n];C=G(n)
for k in C:b=A[t]/N;a=i,j=A[t]%N*3-~b,B[p];q=p<N<(s[i:i-~b],J[i/3+b+N-b*N])>(s[j+t/M:j-~b],J[j/3+b*N]);C[k]=x=a[q];I[x]=k;p+=q;t+=1-q
return C
S=f(map(ord,s)+z*40,u)
for i in G(u):
h-=h>0;j=S[I[i]-1]
while s[i+h]==s[j+h]:h+=1
if(i<t)==(t<j)<=h>m:m=h;L=min(i,j)
print-~L,L+m
이것은 Kärkkäinen과 Sanders의 "Simple Linear Work Suffix Array Construction"에 설명 된 왜곡 알고리즘을 사용합니다. 이 문서에 포함 된 C ++ 구현은 이미 약간 "골프"느낌이 들지만 여전히 더 짧아 질 여지가 많습니다. 예를 들어, 우리는 O(n)
요구 사항 을 위반하지 않고 종이처럼 단락 대신 길이가 1 인 배열에 도달 할 때까지 재귀 할 수 있습니다 .
LCP 부분에 대해서는 Kusai et al.의 "접미어 배열 및 응용 프로그램에서 선형 시간이 가장 긴 공통 접두사 계산"을 따랐습니다.
1 0
가장 긴 공통 부분 문자열이 비어 있으면 프로그램이 출력 합니다.
다음은 C ++ 구현을 조금 더 밀접하게 따르는 이전 버전의 프로그램, 비교를위한 느린 접근 방식 및 간단한 테스트 사례 생성기가 포함 된 일부 개발 코드입니다.
from random import *
def brute(a,b):
L=R=m=0
for i in range(len(a)):
for j in range(i+m+1,len(a)+1):
if a[i:j] in b:
m=j-i
L,R=i,j
return L+1,R
def suffix_array_slow(s):
S=[]
for i in range(len(s)):
S+=[(s[i:],i)]
S.sort()
return [x[1] for x in S]
def slow1(a,b):
# slow suffix array, slow lcp
s=a+'!'+b
S=suffix_array_slow(s)
L=R=m=0
for i in range(1,len(S)):
x=S[i-1]
y=S[i]
p=s[x:]+'#'
q=s[y:]+'$'
h=0
while p[h]==q[h]:
h+=1
if h>m and len(a)==sorted([x,y,len(a)])[1]:
m=h
L=min(x,y)
R=L+h
return L+1,R
def verify(a,b,L,R):
if L<1 or R>len(a) or a[L-1:R] not in b:
return 0
LL,RR=brute(a,b)
return R-L==RR-LL
def rand_string():
if randint(0,1):
n=randint(0,8)
else:
n=randint(0,24)
a='zyxwvutsrq'[:randint(1,10)]
s=''
for _ in range(n):
s+=choice(a)
return s
def stress_test(f):
numtrials=2000
for trial in range(numtrials):
a=rand_string()
b=rand_string()
L,R=f(a,b)
if not verify(a,b,L,R):
LL,RR=brute(a,b)
print 'failed on',(a,b)
print 'expected:',LL,RR
print 'actual:',L,R
return
print 'ok'
def slow2(a,b):
# slow suffix array, linear lcp
s=a+'!'+b+'#'
S=suffix_array_slow(s)
I=S*1
for i in range(len(S)):
I[S[i]]=i
L=R=m=h=0
for i in range(len(S)):
if I[i]:
j=S[I[i]-1]
while s[i+h]==s[j+h]:
h+=1
if h>m and len(a)==sorted([i,j,len(a)])[1]:
m=h
L=min(i,j)
R=L+h
h-=h>0
return L+1,R
def suffix_array(s,K):
# skew algorithm
n=len(s)
s+=[0]*3
n0=(n+2)/3
n1=(n+1)/3
n2=n/3
n02=n0+n2
adj=n0-n1
def radix_pass(a,o,n=n02):
c=[0]*(K+3)
for x in a[:n]:
c[s[x+o]+1]+=1
for i in range(K+3):
c[i]+=c[i-1]
for x in a[:n]:
j=s[x+o]
a[c[j]]=x
c[j]+=1
A=[x for x in range(n+adj) if x%3]+[0]*3
radix_pass(A,2)
radix_pass(A,1)
radix_pass(A,0)
B=[0]*n02
t=m=0
for x in A[:n02]:
u=s[x:x+3]
m+=t<u
t=u
B[x/3+x%3/2*n0]=m
A[:n02]=1/n02*[0]or suffix_array(B,m)
I=A*1
for i in range(n02):
I[A[i]]=i+1
B=[3*x for x in A if x<n0]
radix_pass(B,0,n0)
R=[]
p=0
t=adj
while t<n02:
x=A[t]
b=x>=n0
i=(x-b*n0)*3-~b
j=B[p]
if p==n0 or ((s[i:i+2],I[A[t]-n0+1])<(s[j:j+2],I[j/3+n0]) if b else (s[i],I[A[t]+n0])<(s[j],I[j/3])):R+=i,;t+=1
else:R+=j,;p+=1
return R+B[p:n0]
def solve(a,b):
# linear
s=a+'!'+b+'#'
S=suffix_array(map(ord,s),128)
I=S*1
for i in range(len(S)):
I[S[i]]=i
L=R=m=h=0
for i in range(len(S)):
if I[i]:
j=S[I[i]-1]
while s[i+h]==s[j+h]:
h+=1
if h>m and len(a)==sorted([i,j,len(a)])[1]:
m=h
L=min(i,j)
R=L+h
h-=h>0
return L+1,R
stress_test(solve)
O(n) time
가능합니까?