रैखिक समय में सबसे लंबा सामान्य प्रतिस्थापन


45

यह चुनौती निम्नलिखित समस्या को हल करने के लिए कोड लिखने के बारे में है।

दो तार ए और बी को देखते हुए, आपके कोड को निम्नलिखित गुणों के साथ ए के विकल्प के प्रारंभ और अंत सूचक का उत्पादन करना चाहिए।

  • A के विकल्प में B के कुछ विकल्प से भी मेल खाना चाहिए।
  • ए का कोई विकल्प नहीं होना चाहिए जो पहली संपत्ति को संतुष्ट करता है।

उदाहरण के लिए:

A = xxxappleyyyyyyy

B = zapplezzz

सबस्ट्रिंग appleसूचकांक के साथ 4 8(1 से का अनुक्रमण) एक वैध उत्पादन होगा।

कार्यक्षमता

आप मान सकते हैं कि इनपुट स्थानीय निर्देशिका में एक फ़ाइल में मानक पर या आपकी पसंद का होगा। फ़ाइल प्रारूप बस दो तार होगा, एक नई लाइन द्वारा अलग किया जाएगा। जवाब एक पूर्ण कार्यक्रम होना चाहिए न कि केवल एक फ़ंक्शन।

मैं अंततः http://hgdownload.cse.ucsc.edu/goldenPath/hg38/chromosomes/ में स्ट्रिंग्स से लिए गए दो सब्सट्रिंग्स पर आपके कोड का परीक्षण करना चाहूंगा ।

स्कोर

यह एक मोड़ के साथ कोड-गोल्फ है। आपका कोड O(n)समय पर चलना चाहिए , जहां nइनपुट की कुल लंबाई है।

भाषा और पुस्तकालय

आप किसी भी भाषा का उपयोग कर सकते हैं जिसमें एक स्वतंत्र रूप से उपलब्ध संकलक / दुभाषिया / आदि है। लिनक्स के लिए। आपको केवल इस कार्य को हल करने के लिए डिज़ाइन नहीं किए गए मानक ओपन सोर्स लाइब्रेरीज़ का उपयोग करना चाहिए। विवाद के मामले में, मैं इसे किसी भी पुस्तकालय के रूप में गिना जाऊंगा, जो या तो आपकी भाषा के साथ मानक के रूप में आता है या एक जिसे आप डिफ़ॉल्ट रिपॉजिटरी से एक डिफ़ॉल्ट ubuntu मशीन में स्थापित कर सकते हैं।

उपयोगी जानकारी

रैखिक समय में इस समस्या को हल करने के लिए कम से कम दो तरीके हैं। एक पहले प्रत्यय पेड़ की गणना करना है और दूसरा पहला प्रत्यय सरणी और LCP सरणी की गणना करना है।


4
O(n) timeक्या आप सुनिश्चित हैं कि यह संभव है?
सेवेनकोव एलेक्सी

17
@Lembik क्षमा करें, लेकिन ये बहुत जटिल एल्गोरिदम हैं और कोड की 100+ लाइनों को हल करने के लिए वास्तव में मजेदार नहीं है।
फ्यूजएक्सएक्सएल

4
"उपयोगी जानकारी" के अंतर्गत आपके द्वारा दी गई दूसरी कड़ी का लेख कहता है कि "निर्माण [एक प्रत्यय वृक्ष] के लिए O (N ^ 2) समय की आवश्यकता है"
KSFT

3
@ लेम्बिक आपको बस सवाल [सबसे तेज़-कोड] करना चाहिए, जहां बड़े-ओह नोटेशन जीत में सबसे खराब स्थिति वाला कार्यक्रम। तब आपको कम से कम कुछ उत्तर मिलेंगे, और यह भी कि कोई इसे O (n) में हल कर सकता है , वे जीत जाएंगे।
mbomb007

9
यह मान्य उत्तर प्रति सर्वाधिक हटाए गए प्रश्नों के साथ होना चाहिए ...
FlipTack

जवाबों:


39

पायथन 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 और सैंडर्स द्वारा "सिंपल लाइनियर वर्क सफ़िक्स एरे कंस्ट्रक्शन" में वर्णित तिरछे एल्गोरिथ्म का उपयोग करता है। उस कागज में शामिल सी ++ कार्यान्वयन पहले से ही थोड़ा "गोल्फ" महसूस करता है, लेकिन अभी भी इसे छोटा बनाने के लिए बहुत जगह है। उदाहरण के लिए, हम O(n)आवश्यकता के उल्लंघन के बिना, कागज के रूप में छोटी चक्कर लगाने के बजाय, लंबाई की एक सरणी पर पहुंचने तक पुनरावृत्ति कर सकते हैं।

LCP भाग के लिए, मैंने कुसई एट अल द्वारा "सफ़िक्स एरेस एंड इट्स एप्लिकेशन" में "लीनियर-टाइम लॉन्गेस्ट-कॉमन-प्रीफ़िक्स कम्प्यूटेशन का पालन किया।

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)

1
अगर मैं गलत हूं तो मुझे सुधारो, लेकिन क्या यह वास्तव में 739 बाइट्स नहीं है? मैंने mothereff.in/byte-counter में कॉपी किया और 6-9 लाइनों से 2 रिक्त स्थान हटा दिए, लेकिन मुझे यकीन नहीं है कि यह सही है।
पैट्रिक रॉबर्ट्स

2
@PatrickRoberts वे टैब हैं।
मिच श्वार्ट्ज

2
अच्छा जवाब! आप 2016 से GSACA के एक उपन्यास रेखीय समय SACA पर एक नज़र डालना चाह सकते हैं। संदर्भ कार्यान्वयन टिप्पणियों (24 टिप्पणियों के बिना 170) से भरा 246 लाइनें हैं और बहुत ही गोल्फ लगता है। आप इसे गितुब पर पाएंगे।
क्रिस्टोफ

1
@MitchSchwartz मैं वर्तमान में noPMO पर रहने की कोशिश कर रहा हूं, इसलिए मैं भावनाओं को अभी दृढ़ता से महसूस नहीं कर सकता (शायद असंतुलित मस्तिष्क रसायनों के कारण)। कोड को जल्दी से पढ़ने के समय, मेरा सिंटेक्स गोल्फिंग मोटर स्पॉट किया गया था, और मुझे कोई विशेष भावनाओं को याद नहीं है। क्या आपने एक ही बात के बारे में सोचा या सवाल क्यों? :) अब मैं उत्सुक हूँ।
यति

1
@TuukkaX यह एक दिलचस्प प्रतिक्रिया है जिसकी मुझे उम्मीद नहीं थी। ठीक है, मुझे यकीन नहीं है कि मुझे कुछ विशेष तरीके से इसे फिर से तैयार करना चाहिए, लेकिन यह तथ्य कि आपकी मूल टिप्पणी वास्तव में सही नहीं थी, इसलिए मैंने पूछने का फैसला किया। :)
मिच श्वार्ट्ज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.