Dadas duas cadeias , escrevemos para sua concatenação. Dada uma cadeia e número inteiro , escreve-se para a concatenação de cópias de . Agora, dada uma string, podemos usar essa notação para 'compactá-la', ou seja, pode ser escrito como . Vamos chamar o peso de uma compactação do número de caracteres que aparecem nela; portanto, o peso de é dois, e o peso de (uma compactação de ) é três (separado s são contados separadamente).
Agora considere o problema de calcular a compressão 'mais leve' de uma determinada sequência com . Depois de pensar um pouco, existe uma abordagem de programação dinâmica óbvia que é executada em ou dependendo da abordagem exata.
No entanto, disseram-me que esse problema pode ser resolvido em , embora não seja possível encontrar nenhuma fonte sobre como fazer isso. Especificamente, esse problema foi apresentado em um concurso de programação recente (problema K aqui , últimas duas páginas). Durante a análise, foi apresentado um algoritmo , e no final foi mencionado o limite pseudo-quadrático ( aqui na marca de quatro minutos). Infelizmente, o apresentador apenas se referiu a 'um lema complicado de combinatória de palavras', então agora eu vim aqui para pedir a solução :-)
fonte
Respostas:
Se não estou lhe entendendo mal, acho que a fatoração de custo mínimo pode ser calculada no tempo deO(n2) seguinte maneira.
Para cada índice i, iremos calcular um grupo de valores(pℓi,rℓi) para ℓ=1,2,… , como se segue. Seja p1i≥1 o número inteiro menor, de modo que exista um número inteiro r≥2 satisfazendo S[i−rp1i+1,i−p1i]=S[i−(r−1)p1i+1,i]. For this particular p1i , let r1i be the largest r with this property.
If no such pi exists, set Li=0 so we know there are zero (pℓi,rℓi) values for this index.
Letp2i be the smallest integer strictly bigger than (r1i−1)p1i satisfying, likewise,
S[i−r2ip2i+1,i−p2i]=S[i−(r2i−1)p2i+1,i]
for some r2i≥2 . Like before, take r2i to be the maximal one having fixed p2i .
In general pℓi is the smallest such number strictly bigger than (rℓ−1i−1)pℓ−1i . If no such pℓi exists, then Li=ℓ−1 .
Note that for each index i, we haveLi=O(log(i+1)) due to pℓi values increasing geometrically with ℓ . (if pℓ+1i exists, it's not just strictly bigger than (rℓi−1)pℓi but bigger than that by at least pℓi/2 . This establishes the geometric increase.)
We already observed above that∑jLj=O(∑jlog(j+1))=Θ(nlogn) by bounding the sum term by term. But actually if we look at the whole sum, we can prove something sharper.
Consider the suffix treeT(S←) of the reverse of S (i.e., the prefix tree of S). We will charge each contribution to the sum ∑iLi to an edge of T(S←) so that each edge will be charged at most once. Charge each pji to the edge emanating from nca(v(i),v(i−pji)) and going towards v(i−pji) . Here v(i) is the leaf of the prefix tree corresponding to S[1..i] and nca denotes the nearest common ancestor.
This shows thatO(∑iLi)=O(n) . The values (pji,rji) can be calculated in time O(n+∑iLi) by a traversal of the suffix tree but I will leave the details to a later edit if anyone is interested.
Let me know if this makes sense.
fonte
There is your initial string S of length n. Here is the pseudo-code of the method.
I intentionally gave little details on "end brackets" as it needs lot of steps to stack and unstack which would let the core method unclear. The idea is to test an eventual further contraction inside the first one. for exemple ABCBCABCBC => (ABCBC)² => (A(BC)²)².
So the main point is to look for large periods first. Note that S[i] is the ith term of S skipping any "(", ")" or power.
This is globally O(n²log(n)).
fonte