Eu tenho um problema de pesquisa bastante complexo que consegui reduzir para a descrição a seguir. Estou pesquisando no Google, mas não consegui encontrar um algoritmo que pareça se encaixar perfeitamente no meu problema. Em particular, a necessidade de pular números inteiros arbitrários. Talvez alguém aqui possa me indicar alguma coisa?
Tome uma sequência de números inteiros A, por exemplo (1 2 3 4)
Pegue várias seqüências de números inteiros e teste se algum deles corresponde a A tal que.
- A contém todos os números inteiros na sequência testada
- A ordem dos números inteiros na sequência testada é a mesma em A
- Não nos importamos com números inteiros em A que não estejam na sequência de teste
- Queremos todas as sequências de teste correspondentes, não apenas a primeira.
Um exemplo
A = (1 2 3 4)
B = (1 3)
C = (1 3 4)
D = (3 1)
E = (1 2 5)
B corresponde a
C corresponde a
D não corresponde a A, pois a ordem é diferente
E não corresponde a A, pois contém um número inteiro que não está em A
Espero que esta explicação seja clara o suficiente. O melhor que consegui fazer é criar uma árvore das sequências de teste e repetir A. A necessidade de poder pular números inteiros leva a muitos caminhos de pesquisa sem êxito.
obrigado
Lendo algumas sugestões, sinto que preciso esclarecer alguns pontos que deixei muito vagos.
Números repetidos são permitidos; de fato, isso é muito importante, pois permite que uma única sequência de teste corresponda a A de várias maneiras
A = (1234356), B = (236), as correspondências podem ser -23 --- 6 ou -2--3-6
Eu espero que exista um número muito grande de seqüências de teste, pelo menos em milhares e a sequência A tenderá a ter um comprimento máximo de talvez 20. Portanto, simplesmente tentar combinar cada sequência de teste uma por uma repetindo a iteração se torna extremamente ineficiente.
Desculpe se isso não estava claro.
fonte
Respostas:
Hmm, eu posso pensar em dois possíveis algoritmos: uma varredura linear através da sequência A ou a construção de um dicionário com busca constante dos índices.
Se você estiver testando muitas subsequências potenciais B contra uma única sequência maior A , sugiro que você use a variante com o dicionário.
Digitalização linear
Descrição
Nós manter um cursor para a sequência de um . Em seguida, percorrer todos os itens na subsequence B . Para cada item, movemos o cursor para frente em A até encontrarmos um item correspondente. Se nenhum item correspondente foi encontrado, B não é uma subsequência.
Isso sempre é executado em O (seq.size) .
Pseudo-código
Estilo imperativo:
Estilo funcional:
Exemplo de implementação (Perl):
Pesquisa de dicionário
Descrição
Mapeamos os itens da sequência A para seus índices. Em seguida, procuramos índices adequados para cada item em B , pulamos os índices que são pequenos e selecionamos o menor índice possível como limite inferior. Quando nenhum índice for encontrado, então B não é uma subsequência.
É executado em algo como O (subseq.size · k) , onde k descreve quantos números duplicados existem
seq
. Mais um O (seq.size) sobrecargaA vantagem desta solução é que uma decisão negativa pode ser alcançada muito mais rapidamente (até o tempo constante), depois que você paga a sobrecarga de criação da tabela de pesquisa.
Pseudo-código:
Estilo imperativo:
Estilo funcional:
Exemplo de implementação (Perl):
Variante de pesquisa de dicionário: Codificação como uma máquina de estados finitos
Descrição
Podemos reduzir ainda mais a complexidade algorítmica para O (subseq.size) se trocarmos mais memória. Em vez de mapear elementos para seus índices, criamos um gráfico em que cada nó representa um elemento em seu índice. As arestas mostram possíveis transições, por exemplo, a sequência
a, b, a
teria as arestasa@1 → b@2, a@1 → a@3, b@2 → a@3
. Este gráfico é equivalente a uma máquina de estados finitos.Durante a pesquisa, mantemos um cursor que inicialmente é o primeiro nó da árvore. Em seguida, caminhar à beira de cada elemento na sublista B . Se não existir essa aresta, B não será uma sub-lista. Se após todos os elementos o cursor contiver um nó válido, B será uma sub-lista.
Pseudo-código
Estilo imperativo:
Estilo funcional:
Exemplo de implementação (Perl):
fonte
study
funciona e se os algoritmos aplicados podem ter alguma aplicação prática aqui?study
tinha construído tabelas de pesquisa de caracteres para posições anteriormente, não muito diferente da minha segunda solução.Aqui está uma abordagem prática que evita "o trabalho duro" de implementar seu próprio algoritmo e também evita "reinventar a roda": utilize uma expressão regular mecanismo de para o problema.
Basta colocar todos os números de A em uma sequência e todos os números de B em uma sequência separados pela expressão regular
(.*)
. Adicione um^
personagem no início e$
no final. Em seguida, deixe seu mecanismo de expressão regular favorito procurar todas as correspondências. Por exemplo, quandoA = (1234356), B = (236)
criar um exp exp para B como
^(.*)2(.*)3(.*)6(.*)$
. Agora execute uma pesquisa global regexp. Para descobrir em quais posições A sua correspondência subsequente, basta verificar o comprimento das 3 primeiras sub-correspondências.Se o seu intervalo de números inteiros deixar de 0 a 9, considere codificá-los com uma única letra primeiro para que isso funcione, ou será necessário adaptar a ideia usando um caractere de separação.
Obviamente, a velocidade dessa abordagem dependerá muito da velocidade do mecanismo reg exp que você está usando, mas existem mecanismos altamente otimizados disponíveis, e acho que será difícil implementar um algoritmo mais rápido "pronto para uso" .
fonte
Esse algoritmo deve ser bastante eficiente se obter o comprimento e iterar a sequência for eficiente.
sequence
e quanto menorsubsequence
sequence
.sequence
igual ao número na posição atual desubsequence
sequence
mais umasubsequence
no final dosequence
fonte