시간의 워드 분해 그 안에

두 개의 문자열 주어지면 연결을 위해 를 씁니다 . 문자열이 주어 정수 , 우리는 물품 의 연결을 위해 사본 . 이제 문자열이 주어지면이 표기법을 사용하여 ‘압축’할 수 있습니다. 즉 는 로 작성 될 수 있습니다 . 압축 가중치는 그 안에 나타나는 문자 수를 나타내므로 의 가중치는 2이고 ( 의 압축) 의 는 3입니다 (갈라진

S1,S2

S1S2

S

k1

(S)k=SSS

k

S

AABAAB

((A)2B)2

( ( A ) 2 B 2 ) ( A B ) 2 A A B A B A A

((A)2B2)

(AB)2A

ABABA

A

들)을 별도로 계산됩니다.

이제 주어진 문자열의 ‘가벼운’압축 컴퓨팅의 문제를 고려 함께 . 약간의 생각 후에 정확한 접근법에 따라 또는 에서 실행되는 명확한 동적 프로그래밍 접근법이 있습니다.

S

|S|=n

O(n3logn)

O(n3)

그러나이 문제를 시간에 해결할 수 있다고 들었지만이 작업을 수행하는 방법에 대한 소스를 찾을 수는 없습니다. 구체적으로,이 문제는 최근 프로그래밍 경연 대회에서 발생했습니다 (문제 K 여기 , 마지막 두 페이지). 분석하는 동안 알고리즘이 제시되었고, 마지막에 의사 2 차 경계가 언급되었습니다 ( 여기서는 4 분 표시). 슬프게도 발표자는 ‘복잡한 단어 조합론 정리’만을 언급 했으므로 이제 해결책을 찾기 위해 여기에 왔습니다.

O(n2logn)

O(n3logn)



답변

내가 당신을 오해하지 않는다면, 최소 비용 인수 분해는 다음과 같이 시간으로 계산 될 수 있다고 생각합니다 .

O(n2)

각 인덱스 i에 대해 다음과 같이 대한 여러 값 을 계산 합니다. 하자 정수가되도록 정수 최소치 만족이 특정 경우 이이 특성을 가진 가장 큰 이되게하십시오. 그러한 가 존재 하지 않으면 설정 대해 0 값이 있음을 알 수 있습니다.

(pi,ri)

=1,2,

pi11

r2

S[irpi1+1,ipi1]=S[i(r1)pi1+1,i].

pi1

ri1

r

pi

Li=0

(pi,ri)

하자 보다 엄격하게 더 작은 정수 만족 마찬가지로

일부 입니다 . 이전과 마찬가지로 를 고정 가진 최대 값으로 사용하십시오 . 일반적으로 은 보다 엄격하게 큰 숫자 입니다. 그러한 이 입니다.

pi2

(ri11)pi1

S[iri2pi2+1,ipi2]=S[i(ri21)pi2+1,i]

ri22

ri2

pi2

pi

(ri11)pi1

pi

Li=1

각 인덱스 i에 대해 값이 과 함께 기하학적으로 증가 하기 때문에 있습니다. ( 이 존재하는 경우 보다 엄격하게 크지 않고 최소한 보다 큰 것입니다 . 이것은 기하학적 인 증가를 설정합니다. )

Li=O(log(i+1))

pi

pi+1

(ri1)pi

pi/2

이제 모든 값이 우리에게 주어 졌다고 가정 하십시오. 최소 비용은 재발

에 대한 것으로 이해된다 우리가 설정 . 테이블은 시간 있습니다.

(pi,ri)

dp(i,j)=min{dp(i,j1)+1,min(dp(i,jrjpj)+dp(jrjpj+1,jpj))}

i>j

dp(i,j)=+

O(n2+njLj)

우리는 이미 . 그러나 실제로 우리가 전체의 합계를 보면, 더 날카로운 것을 증명할 수 있습니다.

jLj=O(jlog(j+1))=Θ(nlogn)

의 반대의 접미사 트리 (즉, 의 접두사 트리)를 고려하십시오. 우리는 합계 에 대한 각 기부금을 가장자리에 청구하여 각 가장자리에 최대 한 번 청구됩니다. 각각의 를 하고 쪽으로 이동 하는 가장자리까지 충전 하십시오 . 여기서 는 해당하는 접두사 트리의 잎 이고 nca는 가장 가까운 공통 조상을 나타냅니다.

T(S)

S

iLi

T(S)

pij

nca(v(i),v(ipij))

v(ipij)

v(i)

S[1..i]

이것은 입니다. 값 은 접미사 트리의 순회를 통해 시간 에서 계산할 수 있지만 관심이있는 사람은 나중에 편집 할 세부 사항을 남겨 둡니다.

O(iLi)=O(n)

(pij,rij)

O(n+iLi)

이것이 의미가 있는지 알려주십시오.


답변

길이가 n 인 초기 문자열 S가 있습니다. 다음은 메소드의 의사 코드입니다.

next_end_bracket = n
for i in [0:n]: # main loop

    break if i >= length(S) # due to compression
    w = (next_end_bracket - i)# width to analyse

    for j in [w/2:0:-1]: # period loop, look for largest period first
        for r in [1:n]: # number of repetition loop
            if i+j*(r+1) > w:
                break r loop

            for k in [0:j-i]:
                # compare term to term and break at first difference
                if S[i+k] != S[i+r*j+k]:
                    break r loop

        if r > 1:
            # compress
            replace S[i:i+j*(r+1)] with ( S[i:i+j] )^r
            # don't forget to record end bracket...
            # and reduce w for the i-run, carrying on the j-loop for eventual smaller periods.
            w = j-i

핵심 방법이 명확하지 않은 스택 및 언 스택에 많은 단계가 필요하기 때문에 의도적으로 “엔드 브래킷”에 대한 세부 사항을 거의 제공하지 않았습니다. 아이디어는 첫 번째 내부의 최종 수축을 테스트하는 것입니다. 예를 들어 ABCBCABCBC => (ABCBC) ² => (A (BC) ²) ².

요점은 큰 기간을 먼저 찾는 것입니다. S [i]는 “(“, “)”또는 전력을 건너 뛰는 S의 i 번째 항입니다.

  • i- 루프는 O (n)입니다
  • j- 루프는 O (n)
  • r + k- 루프는 첫 번째 차이에서 멈춤에 따라 O (log (n))입니다.

이것은 전 세계적으로 O (n²log (n))입니다.


답변