가장 짧은 가장 긴 공통 서브 시퀀스 코드


11

가장 긴 공통 서브 시퀀스 문제를 해결하기 위해 가능한 가장 짧은 코드를 찾는 것으로 구성된 SLCSC 문제를 해결하는 작업 .

둘 이상의 문자열에 대한 LCS 문제에 유효 용액 S (1) , ... S 여기서 n은 임의의 문자열 인 T 의 문자되도록 최대 길이 T는 모두에 나타나는 S I을 과 동일한 순서로, T .

참고 T가 없습니다은 서브가 될 문자열S .

문자열 axbycz과는 xaybzc길이 3의 8 개 공통 서브 시퀀스를 가지고 :

abc abz ayc ayz xbc xbz xyc xyz

이 중 하나는 LCS 문제에 대한 올바른 솔루션입니다.

세부

위에서 설명한대로 LCS 문제를 해결하는 프로그램 또는 함수를 작성하여 다음 규칙을 준수하십시오.

  • 입력은 소문자 만 포함하는 두 개 이상의 문자열로 구성됩니다.

    해당 문자열을 문자열 배열 또는 선택한 구분 기호가있는 단일 문자열로 읽을 수 있습니다.

  • 코드는 문제에 대한 가능한 해결책 중 하나를 출력해야하며, 선택적으로 줄 바꿈이 있거나 따옴표로 묶어야합니다.

  • 문자열이 1000 자보다 짧고 최대 20 개의 문자열이 있다고 가정 할 수 있습니다.

    이러한 제한 내에서 코드는 이론상 예상대로 작동해야합니다 (무제한 시간과 메모리 제공).

  • 코드는 내 컴퓨터 (Intel Core i7-3770, 16 GiB RAM)에서 1 시간 이내에 다음 섹션의 결합 된 테스트 사례를 완료해야합니다.

    가능한 모든 하위 시퀀스를 단순히 반복하는 접근 방식은 시간 제한을 준수하지 않습니다.

  • 와 같은이 작업을 사소한 내장 기능을 사용하는 LongestCommonSequence것은 허용되지 않습니다.

표준 규칙이 적용됩니다.

테스트 사례

a
ab

산출: a


aaaaxbbbb
bbbbxcccc
ccccxaaaa

산출: x


hxbecqibzpyqhosszypghkdddykjfjcajnwfmtfhqcpavqrtoipocijrmqpgzoufkjkyurczxuhkcpehbhpsuieqgjcepuhbpronmlrcgvipvibhuyqndbjbrrzpqbdegmqgjliclcgahxoouqxqpujsyfwbdthteidvigudsuoznykkzskspjufgkhaxorbrdvgodlb
qnnprxqpnafnhekcxljyysobbpyhynvolgtrntqtjpxpchqwgtkpxxvmwwcohxplsailheuzhkbtayvmxnttycdkbdvryjkfhshulptkuarqwuidrnjsydftsyhuueebnrjvkfvhqmyrclehcwethsqzcyfvyohzskvgttggndmdvdgollryqoswviqurrqhiqrqtyrl

출력 : hxbbpyhogntqppcqgkxchpsieuhbncvpuqndbjqmclchqyfttdvgoysuhrrl또는 동일한 길이의 다른 공통 서브 시퀀스


riikscwpvsbxrvkpymvbbpmwclizxlhihiubycxmxwviuajdzoonjpkgiuiulbjdpkztsqznhbjhymwzkutmkkkhirryabricvhb
jnrzutfnbqhbaueicsvltalvqoorafnadevojjcsnlftoskhntashydksoheydbeuwlswdzivxnvcrxbgxmquvdnfairsppodznm
kzimnldhqklxyezcuyjaiasaeslicegmnwfavllanoolkhvqkjdvxrsjapqqwnrplcwqginwinktxnkfcuuvoyntrqwwucarfvjg

출력 : icsvllvjnlktywuar또는 동일한 길이의 다른 공통 서브 시퀀스


rblartqkfggrjpiipuzzypkycnyckkcqceeujiyy
yfpnedyjtiwrhyuktripdwyvgkblzodeufkelhub
ywcyboxwqkibwvredkrbdsyudkulpvmhixeqxynh
bnxwahbzhwjxkotnvbxrojkkldtsodtjmvdrmbgr

출력 : krkk또는 동일한 길이의 다른 공통 서브 시퀀스


bwfscmotshoczmduwaev
coywaaizdaxjovipsmeh
dobzcpoiedenzlfdjpiu
bbhfeqscvvbwkuoxdoge
drqrzwbcpcsvneodelja

출력 : code또는 동일한 길이의 다른 공통 서브 시퀀스


nqrualgoedlf
jgqorzglfnpa
fgttvnogldfx
pgostsulyfug
sgnhoyjlnfvr
wdttgkolfkbt

출력 : golf또는 동일한 길이의 다른 공통 서브 시퀀스


epopyfuhgowedpiqpgfj
ddxyestqynpwmytxhozm
ptubgzyqqksieoovuezv
tovotqmnhgzttfpywjgr
aomvytkgaijlgqzkljls
vzvxpaixrnprxvenbbuo
syfuwxlpcyontqlmfvib
arxleuomstkjegpduwcx
xgqrxaopouvkvwgbzewn
yggunddigctgpnuztzai
izroomywwztdymqszsuo
kiawjnxjncdtufhkrjsp

출력 : 빈 문자열



@NotthatCharles 전부는 아닙니다. 이 질문은 입력으로 두 개의 문자열 만 제공하며 시간 제한은 없습니다. 기존의 모든 답변은이 질문의 규칙을 준수하기에는 너무 느린 크기의 접근 방식을 사용합니다.
Dennis

마지막 예제는 계산하는 데 가장 오랜 시간이 걸리지 만, 모든 문자열에 나타나지 않는 모든 문자를 먼저 제거하면 빈 문자열을 출력하는 것이 쉽지 않습니다. 사용 된 모든 문자가 모든 문자열에 나타나고 LCS가 5 자 이상인 곳에 같은 수의 문자열과 문자열 길이를 가진 다른 예를 추가 할 수 있습니까? : 같은 뭔가 ghostbin.com/paste/x9caq
Tyilo

@Tylio 문자열에 더 이상 공통 문자가없는 경우 재귀를 조기에 종료하는 일부 논리를 통합하는 것은 마지막 테스트 사례와 거의 같습니다.
Dennis

@Dennis 그래서 솔루션이 20 개의 임의 길이 1000 문자열로 합리적인 시간에 실행될 수 없어야합니까?
Tyilo

답변:


4

CJam, 31

q~L{_:&\f{_2$f#:).>j+}{,}$W>s}j

온라인으로 사용해보십시오

Dennis 덕분에 9 바이트 골프!

설명:

이 알고리즘은 하위 시퀀스의 첫 번째 위치에 대해 가능한 모든 문자를 시도하고 해당 문자가 처음 발생한 후 각 문자열을 하위 문자열로 바꾼 다음 메모를 사용하여 재귀 적으로 호출합니다.

q~          read and evaluate the input (taken as an array)
L{…}j       execute block with recursive memoization and no starting values
  _         duplicate the array of strings
  :&\       intersect the strings as character sets and move before the array
             these are all the possible characters for the sequence
  f{…}      for each character and the array
    _2$     duplicate the array and the character
    f#      find the character position in each string
    :)      increment the positions (to skip the character)
    .>      slice each string starting at the corresponding position
    j       call the j block recursively
    +       concatenate the starting character with the result
  {,}$      sort resulting strings (one for each character) by length
  W>        keep only the last element, if any
  s         convert (from 0/1-string array) to string

5

파이썬 - 665 (644)

들여 쓰기 수준 :

1: space
2: tab
3: tab + space
4: 2 tabs
5: 2 tabs + space

이 코드는 o문자열 목록을 인수로 사용하여 문자열에 대한 LCS 중 하나를 반환 하는 function을 정의합니다 .

def o(t):
 t=[[y for y in x if y in reduce(lambda x,y:x.intersection(y),t,set(t[0]))]for x in t];l=map(len,t);C=[0]*reduce(lambda x,y:x*-~y,l,1);y=lambda z:[x-1for x in z];m=len(t);e=enumerate
 def g(h):
    r,x=0,1
    for k,j in e(h):r+=-~j*x;x*=-~l[k]
    return r
 def f(h):
    i=len(h)
    if i==m:
     b=g(h);c=t[0][h[0]]
     for k,j in e(h):
         if t[k][j]!=c:break
     else:C[b]=1+C[g(y(h))];return
     r=0
     for k,_ in e(h):a=h[:];a[k]-=1;r=max(r,C[g(a)])
     C[b]=r;return
    for j,_ in e(t[i]):f(h+[j])
 def p(h):
    if min(h)==-1:return''
    v=C[g(h)]
    for k,_ in e(h):
        a=h[:];a[k]-=1
        if v==C[g(a)]:return p(a)
    return p(y(h))+t[0][h[0]]
 f([]);return p(y(l))

테스트 코드 :

tests = [
"""
a
ab
""",
"""
aaaaxbbbb
bbbbxcccc
ccccxaaaa
""",
"""
hxbecqibzpyqhosszypghkdddykjfjcajnwfmtfhqcpavqrtoipocijrmqpgzoufkjkyurczxuhkcpehbhpsuieqgjcepuhbpronmlrcgvipvibhuyqndbjbrrzpqbdegmqgjliclcgahxoouqxqpujsyfwbdthteidvigudsuoznykkzskspjufgkhaxorbrdvgodlb
qnnprxqpnafnhekcxljyysobbpyhynvolgtrntqtjpxpchqwgtkpxxvmwwcohxplsailheuzhkbtayvmxnttycdkbdvryjkfhshulptkuarqwuidrnjsydftsyhuueebnrjvkfvhqmyrclehcwethsqzcyfvyohzskvgttggndmdvdgollryqoswviqurrqhiqrqtyrl
""",
"""
riikscwpvsbxrvkpymvbbpmwclizxlhihiubycxmxwviuajdzoonjpkgiuiulbjdpkztsqznhbjhymwzkutmkkkhirryabricvhb
jnrzutfnbqhbaueicsvltalvqoorafnadevojjcsnlftoskhntashydksoheydbeuwlswdzivxnvcrxbgxmquvdnfairsppodznm
kzimnldhqklxyezcuyjaiasaeslicegmnwfavllanoolkhvqkjdvxrsjapqqwnrplcwqginwinktxnkfcuuvoyntrqwwucarfvjg
""",
"""
rblartqkfggrjpiipuzzypkycnyckkcqceeujiyy
yfpnedyjtiwrhyuktripdwyvgkblzodeufkelhub
ywcyboxwqkibwvredkrbdsyudkulpvmhixeqxynh
bnxwahbzhwjxkotnvbxrojkkldtsodtjmvdrmbgr
""",
"""
bwfscmotshoczmduwaev
coywaaizdaxjovipsmeh
dobzcpoiedenzlfdjpiu
bbhfeqscvvbwkuoxdoge
drqrzwbcpcsvneodelja
""",
"""
nqrualgoedlf
jgqorzglfnpa
fgttvnogldfx
pgostsulyfug
sgnhoyjlnfvr
wdttgkolfkbt
""",
"""
epopyfuhgowedpiqpgfj
ddxyestqynpwmytxhozm
ptubgzyqqksieoovuezv
tovotqmnhgzttfpywjgr
aomvytkgaijlgqzkljls
vzvxpaixrnprxvenbbuo
syfuwxlpcyontqlmfvib
arxleuomstkjegpduwcx
xgqrxaopouvkvwgbzewn
yggunddigctgpnuztzai
izroomywwztdymqszsuo
kiawjnxjncdtufhkrjsp
"""
]

for s in tests:
 print o(s.strip().split())

내 컴퓨터에서 테스트를 실행하는 데 걸리는 시간 :

$ time python 52808-shortest-longest-common-subsequence-code-golfed.py
a
x
hecbpyhogntqtpcqgkxchpsieuhbncvhuqndbjqmclchqyfhtdvgoysuhrrl
icsvllvanlktywuar
krkk
code
golf

        9.03 real         8.99 user         0.03 sys

1
코드를 666 바이트로 가져 오려면 바이트를 추가해야합니다. 그래서 금속. \ m /
Alex A.

@AlexA. 그래도 바이트를 계산할 때 마지막 줄에 줄 바꿈이 포함되어 있음을 알았습니다.
Tyilo

도움이 될만한 몇 가지 작은 개선 사항이 있습니다. 첫째, 당신이 어디에 있든 (n+1), 그것을 -~n2 바이트를 절약하기 위해 그것을 바꿀 수 있습니다 . 또한을 사용 map하는 곳이면 lambda목록 이해를 대신 사용하십시오. 예를 들어 map(lambda x:x-1,z)로 변경하여 3 바이트를 줄일 수 있습니다 [~-x for x in z].
Kade

r,x=r+(j+1)*x,x*(l[k]+1)로 단축 할 수 있습니다 r+=(j+1)*x;x*=(l[k]+1). 또한 한 곳에서만 사용 u=...되므로 필요하지 않습니다 u. 그 코드를 문자로 바꾸십시오 u.
mbomb007

@ Vioz-와 mbomb007 감사합니다.
Tyilo

4

Pyth, 59 58 55 35 바이트

L&@Fb?+yPMbeeb@FeMbeolNmyXJbdP@bdlb

@isaacg 덕분에 무려 20 바이트를 줄였습니다!

55 바이트 버전 :

DCHR?k!&.AH@FH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

(접기 연산자) 로 변경 .U@bZ하여 3 바이트를 자릅니다 @F.

58 바이트 버전 :

DCHR?k!&.AH.U@bZH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

부울 조건부 형식을 변경하여 바이트를 자릅니다.

59 바이트 버전 :

DCHR?k|!.AH!.U@bZH?+Cm<1dHeeHql{medH1h.MlZ.eC++<Hk]<1b>HhkH

힘들었다! 파이썬은 계속 segfaulting! 일종의 버그 였지만 최소한의 테스트 사례를 얻을 수 없었습니다. 오 잘

나는 이것 의 알고리즘을 기반으로했다 . 하나는 두 개의 문자열만을 위해 설계된다는 점을 제외하고는 괜찮습니다. 더 많은 작업을 수행하기 위해 약간 조정해야했습니다. 그런 다음 마지막 테스트 사례가 너무 오래 걸리므로 더 많은 공통 문자가 없으면 재귀를 종료하기 위해 추가 검사를 추가해야했습니다.

꽤 느리지 만 1 시간도 채 걸리지 않아야합니다 . 6GB의 RAM으로 Core i3에서 테스트 중이므로 16GB Core i7 이이 문제를 해결해야합니다. :)

또한 Pyth의 자동 메모리 기능을 활용하여 조금 더 빨랐습니다.

편집 : @ 데니스 그것이 통과 말했다!

테스트하려면 다음 줄을 추가하십시오.

CQ

표준 입력 (예 :)을 통해 문자열 목록을 제공하십시오 ['a', 'ab'].

35 바이트 버전에 대한 설명 :

WIP.

55 바이트 버전에 대한 설명 :

DCH                                                        define a function C that takes a list of strings H
   R                                                       return the following expression
    ?                                                      if
      !&.AH@FH                                             there are no more common letters OR all the strings are empty
     k                                                     return the empty string
              ?          ql{medH1                          else if the last character of every string is equal
               +Cm<1dHeeH                                  return the result of adding the last character to recursion with every item without its last character
                                 h.MlZ.eC++<Hk]<1b>HhkH    otherwise, return the largest result of recursing len(H) times, each time with one element's last character cut off

@ 데니스 Ok; 내가 할게
kirbyfan64sos

@ 데니스 업데이트. 지금 다시 시도 할 수 있습니다.
kirbyfan64sos

마지막 테스트 사례가 즉시 완료됩니다.
Dennis

@Dennis YESSSSS !!
kirbyfan64sos

@ kirbyfan64sos segfaults 정보 : 무한 재귀와 같이 재귀 깊이가 너무 높을 때 Pyth segfaults.
isaacg

4

C, 618 564 바이트

d,M,N,A[9999][2];char*(R[9999][20]),b[1000];L(char**s,n){char*j[20],c,a=0;int x[n],y=n-1,z,i,t,m=0,w=1;for(;y;)x[y--]=999;for(;y<N;y++){for(i=0;i<n&&s[i]==R[y][i];i++);if(i/n){a=A[y][0];m=A[y][1];w=0;if(m+d<M||!a)goto J;else{c=a;goto K;}}}for(c=97;w&&c<'{';c++){K:t=1,y=1,z=1;for(i=0;i<n;j[i++]++){for(j[i]=s[i];*j[i]-c;j[i]++)t&=!!*j[i];y&=j[i]-s[i]>x[i]?z=0,1:0;}t&=!y;I:if(t){if(z)for(i=0;i<n;i++)x[i]=j[i]-s[i];d++,t+=L(j,n),d--,m=t>m?a=c,t:m;}}if(w){for(y=0;y<n;y++)R[N][y]=s[y];A[N][0]=a;A[N++][1]=m;}J:if(d+m>=M)M=d+m,b[d]=a;if(!d)N=0,M=0,puts(b);return m;}

그리고 여기에 "가독성"에 대한 설명이 있습니다 :

d,M,N,A[9999][2];
char*(R[9999][20]),b[1000];
L(char**s,n){
    char*j[20],c,a=0;
    int x[n],y=n-1,z,i,t,m=0,w=1;
    for(;y;)
        x[y--]=999;
    for(;y<N;y++){
        for(i=0;i<n&&s[i]==R[y][i];i++);
        if(i/n){
            a=A[y][0];
            m=A[y][1];
            w=0;
            if(m+d<M||!a)
                goto J;
            else{
                c=a;
                goto K;
            }
        }
    }
    for(c=97;w&&c<'{';c++){
        K:
        t=1,
        y=1,
        z=1;
        for(i=0;i<n;j[i++]++){
            for(j[i]=s[i];*j[i]-c;j[i]++)
                t&=!!*j[i];
            y&=j[i]-s[i]>x[i]?z=0,1:0;
        }
        t&=!y;
        I:
        if(t){
            if(z)
                for(i=0;i<n;i++)
                    x[i]=j[i]-s[i];
            d++,
            t+=L(j,n),
            d--,
            m=t>m?a=c,t:m;
        }
    }
    if(w){
        for(y=0;y<n;y++)R[N][y]=s[y];
        A[N][0]=a;
        A[N++][1]=m;
    }
    J:
    if(d+m>=M)
        M=d+m,b[d]=a;
    if(!d)
        N=0,M=0,puts(b);
    return m;
}

신사 숙녀 여러분, 저는 끔찍한 실수를 저질렀습니다. 예전 에는 더 예 뻤고 ... 고 토레스 ... 적어도 지금은 빠릅니다 .

문자 배열과 문자열 수 의 L배열 s을 입력으로받는 재귀 함수 를 정의합니다 n. 이 함수는 결과 문자열을 stdout으로 출력하고 실수로 해당 문자열의 문자로 크기를 반환합니다.

접근

코드가 복잡하지만 여기서의 전략이 너무 복잡하지는 않습니다. 우리는 의사 코드로 설명 할 순진한 재귀 알고리즘으로 시작합니다.

Function L (array of strings s, number of strings n), returns length:

Create array of strings j of size n;

For each character c in "a-z",
    For each integer i less than n,
         Set the i'th string of j to the i'th string of s, starting at the first appearance of c in s[i]. (e.g. j[i][0] == c)
         If c does not occur in the i'th string of s, continue on to the next c.
    end For

    new_length := L( j, n ) + 1; // (C) t = new_length
    if new_length > best_length
        best_character := c; // (C) a = best_character
        best_length := new_length; // (C) m = best_length
    end if
end For

// (C) d = current_depth_in_recursion_tree
if best_length + current_depth_in_recursion_tree >= best_found
     prepend best_character to output_string // (C) b = output_string
     // (C) M = best_found, which represents the longest common substring found at any given point in the execution.
     best_found = best_length + current_depth;
end if

if current_depth_in_recursion_tree == 0
    reset all variables, print output_string
end if 

return best_length

자,이 알고리즘은 그 자체로 꽤 끔찍합니다 (그러나 약 230 바이트에 들어갈 수 있습니다). 이것은 빠른 결과를 얻는 방법이 아닙니다. 이 알고리즘은 문자열 길이에 따라 확장 성이 매우 떨어집니다. 그러나이 알고리즘 더 많은 수의 문자열로 상당히 확장됩니다. 마지막 테스트 사례는 문자열 에 공통된 s문자가 없기 때문에 거의 즉시 해결 c됩니다. 위에서 구현 한 두 가지 주요 트릭이있어 속도가 크게 향상되었습니다.

  • 에 대한 모든 호출에서 L이전에 동일한 입력을 받았는지 확인하십시오. 실제로 정보는 동일한 문자열 집합에 대한 포인터를 통해 전달되므로 실제로 문자열을 비교할 필요가 없으며 위치 만 비교하면 좋습니다. 우리가 전에이 정보를 얻었음을 알게되면 계산을 수행 할 필요가 없지만 (대부분의 경우 출력을 얻는 것이 조금 더 복잡해집니다) 길이를 반환하는 것만으로도 벗어날 수 있습니다. 우리는 않으면 하지 일치하는 항목을 찾아, 미래의 통화를 비교하는 입력 / 출력의 설정을 저장합니다. C 코드에서 두 번째 for루프는 입력과 일치하는 항목을 찾으려고 시도합니다. 알려진 입력 포인터가에 저장되고 R해당 길이 및 문자 출력 값이에 저장됩니다A. 이 계획은 특히 문자열이 길면 런타임에 큰 영향을 미쳤습니다.

  • c에서 의 위치를 ​​찾을 때마다 s우리가 찾은 것이 최적이 아니라는 것을 바로 알 수 있습니다. 의 모든 위치하는 경우 c가 나타납니다 다른 편지의 일부 알려진 위치, 우리는 자동으로 알고 이 것을 c당신이 그것에 하나 더 편지를 넣을 수 있기 때문에, 최적의 문자열로 연결되지 않습니다. 즉, 적은 비용 L으로 큰 문자열 에 대한 수백 번의 호출을 제거 할 수 있습니다 . 위의 C 코드에서, y이 문자가 차선의 문자열로 이어지는 것을 자동으로 알면 z플래그가 설정 되고, 다른 알려진 문자보다 먼저 등장한 문자가 발견되면 플래그가 설정됩니다. 현재 가장 빠른 등장 인물은x. 이 아이디어의 현재 구현은 약간 지저분하지만 많은 경우 성능이 거의 두 배입니다.

이 두 가지 아이디어로 한 시간 안에 끝나지 않은 것은 이제 약 0.015 초가 걸렸습니다.

성능을 향상시킬 수있는 더 많은 작은 트릭이있을 수 있지만이 시점에서 나는 모든 것을 골프 질 할 수있는 능력에 대해 걱정하기 시작했습니다. 나는 여전히 골프에 만족하지 않으므로 나중에 다시 올 것입니다!

타이밍

다음은 몇 가지 테스트 코드입니다. 온라인 에서 테스트 해보십시오 .

#include "stdio.h"
#include "time.h"

#define SIZE_ARRAY(x) (sizeof(x) / sizeof(*x))

int main(int argc, char** argv) {
    /* Our test case */
    char* test7[] = {
        "nqrualgoedlf",
        "jgqorzglfnpa",
        "fgttvnogldfx",
        "pgostsulyfug",
        "sgnhoyjlnfvr",
        "wdttgkolfkbt"
    };

    printf("Test 7:\n\t");
    clock_t start = clock();

    /* The call to L */
    int size = L(test7, SIZE_ARRAY(test7));


    double dt = ((double)(clock() - start)) / CLOCKS_PER_SEC;
    printf("\tSize: %d\n", size);
    printf("\tElapsed time: %lf s\n", dt);

    return 0;
}

최적화 설정이 1.7GHz 인 Intel Core i7 칩 1.7GHz가 장착 된 랩톱에서 OP 테스트 케이스를 실행했습니다 -Ofast. 시뮬레이션에 필요한 최대 712KB가보고되었습니다. 다음은 타이밍과 함께 각 테스트 사례의 예제 실행입니다.

Test 1:
    a
    Size: 1
    Elapsed time: 0.000020 s
Test 2:
    x
    Size: 1
    Elapsed time: 0.000017 s
Test 3:
    hecbpyhogntqppcqgkxchpsieuhbmcbhuqdjbrqmclchqyfhtdvdoysuhrrl
    Size: 60
    Elapsed time: 0.054547 s
Test 4:
    ihicvaoodsnktkrar
    Size: 17
    Elapsed time: 0.007459 s
Test 5:
    krkk
    Size: 4
    Elapsed time: 0.000051 s
Test 6:
    code
    Size: 4
    Elapsed time: 0.000045 s
Test 7:
    golf
    Size: 4
    Elapsed time: 0.000040 s
Test 8:

    Size: 0
    Elapsed time: 0.000029 s


Total time: 0.062293 s

골프를 타면서, 나는 성능을 어느 정도 향상 시켰으며, 사람들은 이전의 618 바이트 솔루션의 무차별 속도 (0.013624 초를 결합하여 모든 테스트 사례를 완료하는 것)를 좋아하는 것처럼 보였으므로 참조를 위해 여기에 남겨 두겠습니다.

d,M,N,A[9999][2];char*(R[9999][20]),b[1000];L(char**s,n){char*j[20],c,a=0;int x[n],y,z,i,t,m=0,w=1;for(y=0;y<n;y++)x[y]=999;for(y=0;y<N;y++){for(i=0;i<n;i++)if(s[i]!=R[y][i])break;if(i==n){a=A[y][0];m=A[y][1];w=0;if(m+d<M||!a)goto J;else{c=a;goto K;}}}for(c=97;w&&c<'{';c++){K:t=1,y=1,z=1;for(i=0;i<n;j[i++]++){for(j[i]=s[i];*j[i]-c;j[i]++)if(!*j[i]){t=0;goto I;}if(j[i]-s[i]>x[i])z=0;if(j[i]-s[i]<x[i])y=0;}if(y){t=0;}I:if(t){if(z){for(i=0;i<n;i++){x[i]=j[i]-s[i];}}d++,t+=L(j,n),d--,m=t>m?(a=c),t:m;}}if(w){for(y=0;y<n;y++)R[N][y]=s[y];A[N][0]=a;A[N++][1]=m;}J:if(d+m>=M)M=d+m,b[d]=a;if(!d)N=0,M=0,puts(b);return m;}

알고리즘 자체는 변경되지 않았지만 새 코드는 나누기와 일부 까다로운 비트 연산에 의존하여 전체 속도가 느려집니다.


비슷한 주제에 대해 가장 빠른 코드 도전 과제를 게시하려고 생각했지만 더 이상 필요하지 않은 것 같습니다. 0.01과 712KB는 놀랍습니다.
Dennis

이것은 단순히 놀랍습니다!
kirbyfan64sos 1

당신의 설명을 살펴보면 도대체 무엇 best_found입니까? 조건부에서 사용될 때 한 번, 재설정 될 때 한 번만 두 번 언급됩니다.
kirbyfan64sos

C 소스를 살펴보면 best_found로 설정된 것 같습니다 best_length + current_depth. 설명에서 아마 언급해야 할 것입니다!
kirbyfan64sos

@ kirbyfan64sos best_found는 실행 시점에서 발견되는 가장 긴 공통 부분 문자열의 길이를 나타내는 전역 정수입니다. 설명에 넣겠습니다!
BrainSteel

1

파이썬 2, 285

암호:

import re
def f(s,a,b):
  if b==[]:return s+f('',[],a)
  if a==[]:return s+max([f(b[0][i],[b[0][i+1:]],b[1:]) for i in range(len(b[0]))],key=len) if b[0]!='' else ''
  return max([f(s,a+[b[0][i.start()+1:]],b[1:]) for i in re.finditer(s[-1],b[0])],key=len) if ~b[0].find(s[-1]) else ''

용법:

print f('',[],['axbycz','xaybzc'])

설명:

이것은 재귀 함수입니다. s우리가 찾고있는 캐릭터입니다. a뒤에 슬라이스 된 문자열 목록을 포함합니다 s. b아직 untouced 문자열 목록을 포함합니다. f가장 긴 공통 문자열을 반환합니다.

첫 번째 조건은 모든 문자열을 다 끝 냈는지 확인합니다. 그렇다면 s일반적인 문자 임을 의미 s하며 더 일반적인 문자를 찾아서 찾습니다.

두 번째 조건은 문자열을 통과하지 않는지 확인합니다. 즉, 문자가없는 것 a==[]입니다 (와 동일 s==''). 그렇다면에서 첫 번째 문자열의 각 문자를 확인합니다 b.

마지막 줄은이 문자열에서 각 항목을 찾아 첫 번째 문자열을 b로 이동 합니다.as

첫 번째 호출에서 s빈 문자열이어야합니다. a빈 목록 b이어야하고 모든 문자열을 포함해야합니다.


2
기본 인수를 사용하여 문자열과 같이 함수에 문자열 만 제공하면됩니다 f(b,s='',a=[]).
feersum
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.