두 개의 문자열 주어지면 연결을 위해 를 씁니다 . 문자열이 주어 정수 , 우리는 물품 의 연결을 위해 사본 . 이제 문자열이 주어지면이 표기법을 사용하여 ‘압축’할 수 있습니다. 즉 는 로 작성 될 수 있습니다 . 압축 가중치는 그 안에 나타나는 문자 수를 나타내므로 의 가중치는 2이고 ( 의 압축) 의 는 3입니다 (갈라진
S1,S2S1S2
S
k≥1
(S)k=SS⋯S
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,…
pi1≥1
r≥2
pi1
ri1
r
pi
Li=0
(piℓ,riℓ)
하자 보다 엄격하게 더 작은 정수 만족 마찬가지로
일부 입니다 . 이전과 마찬가지로 를 고정 가진 최대 값으로 사용하십시오 . 일반적으로 은 보다 엄격하게 큰 숫자 입니다. 그러한 이 입니다.
pi2(ri1−1)pi1
ri2≥2
ri2
pi2
piℓ
(riℓ−1−1)piℓ−1
piℓ
Li=ℓ−1
각 인덱스 i에 대해 값이 과 함께 기하학적으로 증가 하기 때문에 있습니다. ( 이 존재하는 경우 보다 엄격하게 크지 않고 최소한 보다 큰 것입니다 . 이것은 기하학적 인 증가를 설정합니다. )
Li=O(log(i+1))piℓ
ℓ
piℓ+1
(riℓ−1)piℓ
piℓ/2
이제 모든 값이 우리에게 주어 졌다고 가정 하십시오. 최소 비용은 재발
에 대한 것으로 이해된다 우리가 설정 . 테이블은 시간 있습니다.
(piℓ,riℓ)
dp(i,j)=min{dp(i,j−1)+1,minℓ(dp(i,j−rjℓpjℓ)+dp(j−rjℓpjℓ+1,j−pjℓ))}i>j
dp(i,j)=+∞
O(n2+n∑jLj)
우리는 이미 . 그러나 실제로 우리가 전체의 합계를 보면, 더 날카로운 것을 증명할 수 있습니다.
∑jLj=O(∑jlog(j+1))=Θ(nlogn)의 반대의 접미사 트리 (즉, 의 접두사 트리)를 고려하십시오. 우리는 합계 에 대한 각 기부금을 가장자리에 청구하여 각 가장자리에 최대 한 번 청구됩니다. 각각의 를 하고 쪽으로 이동 하는 가장자리까지 충전 하십시오 . 여기서 는 해당하는 접두사 트리의 잎 이고 nca는 가장 가까운 공통 조상을 나타냅니다.
T(S←)S
∑iLi
T(S←)
pij
nca(v(i),v(i−pij))
v(i−pij)
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))입니다.