2012-06-18 5 views
36

시퀀스에서 세 번 이상 반복해야하는 경고가있는 문자열에서 가장 긴 시퀀스를 찾아야합니다. 따라서, 예를 들어, 내 문자열 인 경우 :문자열에서 가장 긴 반복 시퀀스 찾기

그때 나는 값 "helloworld를"반환하기를 원하는

fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld.

나는 이것을 수행하는 몇 가지 방법을 알고 있지만 내가 직면하고있는 문제는 실제 문자열이 어리석게 커지기 때문에시기 적절하게 그것을 할 수있는 방법을 찾고 있다는 것입니다.

+7

이 문제에 대한 정규식 솔루션이 있는지 나는 모른다. 이것은 정규 표현식이 될 수 없지만, 파이썬은 이와 같은 일을하는 비표준 확장을 가질 수 있습니다. 일반적인 경우 이것은 동적 프로그래밍을 사용하여 해결할 수있는 LCS 문제입니다. http://en.wikipedia.org/wiki/Longest_common_subsequence_problem –

답변

30

이 문제는 longest repeated substring problem의 변형이며 suffix trees을 사용하는 해결을위한 O (n) 시간 알고리즘이 있습니다. Wikipedia에서 제안한 아이디어는 접미사 트리 (시간 O (n))를 만들고, 트리의 모든 노드에 하위 노드 수 (DFS를 사용하여 시간 O (n))를 주석으로 추가 한 다음 최소한 3 개의 하위 노드 (DFS를 사용하는 시간 O (n))가있는 트리의 가장 깊은 노드. 이 전체 알고리즘은 시간 O (n)을 필요로합니다.

말하자면, 접미어 트리는 작성하기가 어렵 기 때문에 악의를 띤 빌드를 구현하기 전에 접미어 트리를 구현하는 Python 라이브러리를 찾고 싶을 것입니다. 빠른 Google 검색은 this library으로 바뀌지 만, 좋은 구현인지 잘 모르겠습니다.

희망이 도움이됩니다.

+1

"악명 높게 구성하기가 어렵습니다"- 뭐라고 말합니까? –

+8

@ KonradRudolph- 나는 선형 시간에 접미사 트리를 구성하기위한 "간단한"알고리즘을 모른다. 내가 아는 두 가지 알고리즘 (Ukkonen의 알고리즘과 DC3 알고리즘)은 매우 복잡하며 정확성의 확실한 증거가 없습니다. 즉, 내가 이것에 착각하면, 나는 정정당하는 것을 좋아할 것입니다! – templatetypedef

+0

나는 증명이 사소한 것에 동의한다. 그러나 Ukkonen의 알고리듬에 적용 할 수있는 의사 코드가 존재합니다. 게다가, 선형 시간 알고리즘은 찾기가 어렵지만, 그럼에도 불구하고 실제로 파생 된 비선형 구성 알고리즘이 있습니다. –

0

마음에 온 첫 번째 생각은 점진적으로 더 큰 정규 표현식으로 검색한다 : 코드가 성공적으로 실행

import re 

text = 'fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld' 
largest = '' 
i = 1 

while 1: 
    m = re.search("(" + ("\w" * i) + ").*\\1.*\\1", text) 
    if not m: 
     break 
    largest = m.group(1) 
    i += 1 

print largest # helloworld 

. 시간 복잡도는 적어도 O (n^2) 인 것으로 보입니다.

+0

은'banana'와 함께 작동하지 않습니다. 답은'ana 2 times'이어야합니다. –

3

마지막부터 시작하여 가장 빈번한 요소가 3 번 이상 나타나면 빈도를 세고 중지하십시오.

from collections import Counter 
a='fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld' 
times=3 
for n in range(1,len(a)/times+1)[::-1]: 
    substrings=[a[i:i+n] for i in range(len(a)-n+1)] 
    freqs=Counter(substrings) 
    if freqs.most_common(1)[0][1]>=3: 
     seq=freqs.most_common(1)[0][0] 
     break 
print "sequence '%s' of length %s occurs %s or more times"%(seq,n,times) 

결과 :

>>> sequence 'helloworld' of length 10 occurs 3 or more times 

편집 : 당신은 당신이 작은 길이이어야 임의 입력과 일반 문자열을 취급하고있는 느낌이있는 경우, 당신은 더 나은 (당신이 필요로하는 경우 시작 속도는 작은 부분 문자열을 사용하고 적어도 세 번 나타나면 찾을 수 없을 때 중지하십시오.

from collections import Counter 
a='fdwaw4helloworldvcdv1c3xcv3xcz1sda21f2sd1ahelloworldgafgfa4564534321fadghelloworld' 
times=3 
for n in range(1,len(a)/times+1): 
    substrings=[a[i:i+n] for i in range(len(a)-n+1)] 
    freqs=Counter(substrings) 
    if freqs.most_common(1)[0][1]<3: 
     n-=1 
     break 
    else: 
     seq=freqs.most_common(1)[0][0] 
print "sequence '%s' of length %s occurs %s or more times"%(seq,n,times) 

위와 같은 결과입니다.

+0

즉,'M = len (a)/N' (N은 최소 담당자 수)으로 시작하는 M 항목의 각 부분 집합을 빌드하고 담당자를 계산합니다 각각의 하위 문자열에 발생 횟수가 = N 이상인 경우 M에서 1을 빼고 다시 시도하십시오. 예? – PaulMcG

+0

@PaulMcGuire 정확히 –

+0

나는 반대 방향 (비슷한 것에서 큰 것)으로 비슷한 것을 시도하고있다. 어떤 아이디어가 당신의 접근 방식에있어 시간 복잡성이라고 생각하십니까? –

9

defaultdict를 사용하여 입력 문자열의 각 위치로 시작하는 각 부분 문자열을 집계하십시오. OP는 겹쳐진 성냥이 포함되어야하는지 포함되어서는 안되는지 명확하지 않았지만,이 무차별 방식에는 그것도 포함됩니다.

from collections import defaultdict 

def getsubs(loc, s): 
    substr = s[loc:] 
    i = -1 
    while(substr): 
     yield substr 
     substr = s[loc:i] 
     i -= 1 

def longestRepetitiveSubstring(r, minocc=3): 
    occ = defaultdict(int) 
    # tally all occurrences of all substrings 
    for i in range(len(r)): 
     for sub in getsubs(i,r): 
      occ[sub] += 1 

    # filter out all substrings with fewer than minocc occurrences 
    occ_minocc = [k for k,v in occ.items() if v >= minocc] 

    if occ_minocc: 
     maxkey = max(occ_minocc, key=len) 
     return maxkey, occ[maxkey] 
    else: 
     raise ValueError("no repetitions of any substring of '%s' with %d or more occurrences" % (r,minocc)) 

인쇄 : 당신이 입력 문자열을 반대로하면

('helloworld', 3) 
+3

저는이 솔루션을 정말 좋아하지만 불행히도 제 문자열은 일반적으로 너무 큽니다. 그러나 나는 아주 잘 준 원래 사례를 해결하기 때문에 Google을 통해 여기에 방문하는 사람들에게 귀하의 대답이 매우 유용 할 것입니다. – Snesticle

0

는 다음 (.+)(?:.*\1){2}
같은 정규식에 공급 그것은 당신에게 가장 긴 문자열을 제공해야 3 회 반복.(답에 대한 역 캡처 그룹 1)

편집 : 나는이 방법을 취소 말을
. 그것은 첫 번째 경기에 의존합니다. 지금까지 curr 길이 대 최대 길이를 테스트하지 않으면, 반복 루프에서 정규 표현식이 작동하지 않습니다.

관련 문제