Contagem de substrings distintos na cadeia dentro da faixa


7

Tendo a string de comprimento , encontrar a contagem de substrings distintos pode ser feito em tempo linear usando o array LCP. Em vez de solicitar substrings exclusivos, conte na cadeia inteira , a consulta contém a indexação que está solicitando a contagem de substring distintas dentro do intervalo de consulta especificado para a cadeia .SnSq(i,j)0ij<nS[i..j]

Minha abordagem é apenas aplicar a construção de tempo linear da matriz LCP para cada consulta. Dá complexidade . O número de consultas pode aumentar para a ordem de portanto, responder a todas as consultas torna .O(|q|n)nO(n2)

Pode ser feito melhor do que o tempo linear para cada consulta?

Em geral, se um processo de substring de string para o qual já temos matriz de sufixos, árvore de sufixos, matriz lcp, essas estruturas não são mais relevantes e devem ser construídas do zero novamente?


O tamanho da entrada e da saída parece ser um limite inferior natural.
Raphael

11
Não tenho tempo para pensar nisso, mas é bastante padrão construir árvores de segmentos a partir dessas estruturas complexas (em programação competitiva), talvez seja o caso de matrizes de sufixo / árvores / etc. Você só precisa ser inteligente ao definir uma operação rápida de "combinação" (que será usada para um nó pai com seus filhos ou no final para combinar os resultados de todas as folhas que cobrem seu intervalo).
Md5

O número de pedidos de informação é o número de pares ordenados que é , de modo que a complexidade deve seri,j(n(n+1))/2O(n3)
user11171

@ MD5 Eu não acho que uma solução baseada em árvore de segmentos (ou árvore de Fenwick) funcione porque o número de substrings não possui inversão aditiva.
precisa saber é o seguinte

Respostas:


0

A questão não motiva o número de consultas sendo , o que parece ser o pior caso arbitrário, pois o número de possíveis consultas únicas é o número de pares ordenados e, portanto, .O(n)O(n2)

Aqui estão duas soluções diferentes com melhor complexidade de tempo para o caso base em árvores de sufixos (implícitas) construídas de forma incremental com o algoritmo de Ukkonen . Ambas as soluções são baseadas no pré-processamento e possuem complexidade onde é o conjunto de consultas. A segunda solução é executada em se todas as consultas tiverem a mesma largura.O(n2)O(n2+|Q|)QO(n+|Q|)

Solução 1 - Pré-processe todas as consultas exclusivas

Repetir os sufixos de . Para cada sufixo , construa a árvore de sufixos com o algoritmo de Ukkonen. Após atualizar para a árvore de sufixos atual, armazene o tamanho da árvore em uma matriz na posição . Uma consulta para o intervalo é respondida pelo elemento da matriz em .SSi=S[i..n]Sij(i,i+j1)[x,y](x,y)

O tamanho da árvore do sufixo pode ser armazenado junto com a árvore do sufixo e atualizado em tempo constante a cada etapa, modificando o procedimento de atualização no algoritmo de Ukkonen. Para cada atualização, o tamanho aumenta pelo número atual de folhas.

Solução 2 - Pré-processar larguras de consulta exclusivas

Essa solução é mais difícil de implementar, mas requer menos trabalho de pré-processamento se houver poucas larguras de consulta. O pré-processamento leva tempo se houver apenas uma largura de consulta.O(n)

Para cada largura de consulta , use uma janela deslizante de largura construa incrementalmente uma árvore de sufixos. Remova o sufixo iniciando um caractere à esquerda da janela e remova o sufixo mais longo da árvore. Em cada etapa, o número atual de substrings na janela deslizante é o tamanho da árvore.ww

Todas as consultas podem ser respondidas em tempo linear usando os resultados da pré-computação.

Nota: a remoção do sufixo mais longo pode ser feita removendo a folha mais antiga da árvore do sufixo. Não é fácil de implementar corretamente.


Isso parece um pouco errado. A tarefa não é responder a todas as possíveis perguntas , mas responder a algumas consultas dadas. O(n2)q
Gassa

Eu respondi a pergunta para o caso geral, que era o ponto da pergunta. No caso especial em que o número de consultas é baixo, a solução proposta pelo autor da pergunta seria mais rápida na prática. O número de saídas de uma solução válida é , que é do tamanho (desconsiderando consultas duplicadas), portanto, qualquer solução possível deve ser executada em ou mais lenta. Minha solução proposta leva tempo para pré-processamento e, em seguida, cada consulta pode ser respondida em tempo constante. qO(n2)O(n2)O(n2)
precisa saber é o seguinte

Novamente, é um parâmetro. A questão está explicitamente interessada no número de consultas sendo , não nem . A resposta para consultas é do tamanho que não precisa ser . qqΘ(n)Θ(1)Θ(n2)qΘ(q)Θ(n2)
Gassa

Por que o número de consultas seria da ordem ? Parece uma condição arbitrária, se não uma supervisão do autor. n
user11171

Toda a declaração do problema é do mesmo tipo de arbitrária. No entanto, é assim que se parece com um problema típico de estrutura de dados em programação competitiva, portanto, é improvável que consultas sejam o que o OP procura. Eu aposto que e são parâmetros independentes de a ou mais, e o prazo é de alguns segundos, para que uma solução , mas algo melhor como não. n2nq1100000O(nq)O(nq)
Gassa

0

Existe uma solução offline .O(nn+|Q|n)

  1. Classifique os elementos de em ordem crescente de .(i,j)Qj
  2. Distribua-os em buckets, para que entre no número do bucket .n(i,j)in
  3. Para cada bloco que começa em cada consulta nele, crie uma árvore de sufixos para .b(i,j)S[b,j]
  4. Para cada consulta em um intervalo, remova caracteres redundantes da esquerda e relate a resposta.

O passo 3 pega para cada bucket, porque usamos o algoritmo de Ukkonen segue em ordem crescente.O(n)j

A etapa 4 usa para cada consulta, porque remover sufixos mais longos da árvore leva . Observe que você pode usar uma camada indireta para evitar modificações na árvore de sufixos original.O(n)nO(n)


O número de substrings distintos é o número de caminhos na árvore de sufixos que começam na raiz e terminam em um nó com apenas uma folha abaixo, correto? Você armazena essas contagens de caminho explicitamente nas notas? Se sim, como atualizar as coisas ao remover o primeiro caractere no tempo O (1)? Pode haver até deles (no caso em que o primeiro caractere é único dentro do bloco). Se não, como você os computa em tempo real? n
Jrandom_hacker

@j_random_hacker O algoritmo de Ukkonen constrói a chamada árvore de sufixos implícitos. O número de substrings distintos é apenas a soma dos comprimentos de suas bordas (ou seja, o tamanho da trie correspondente).
Dmitri Urbanowicz 08/07/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.