Seja uma coleção de seqüências de caracteres sobre o alfabeto que no total contêm símbolos.
Sua tarefa é classificar cada uma das cadeias internamente e, em seguida, classificar as cadeias resultantes em ordem lexicográfica. (Seu algoritmo não precisa operar dessa maneira.)
Exemplo:
Entrada: 33123 15 1 0 54215 21 12
Saída: 0 1 12 12 12333 12455 15
Eu encontrei uma maneira de fazê-lo no tempo e no espaço .
O espaço é maior que o tempo, porque eu uso uma matriz inteligente que permite criar uma matriz com tamanho e fornecer valores iniciais para todas as células em .
Usei a classificação de bucket para classificar cada sequência de caracteres ( tempo e espaço) e árvores de palavras para classificar a coleção si ( tempo e espaço). mas minha solução é muito complicada.
Alguém tem uma solução melhor, com tempo e menos espaço, ou mais rápido que ?
A solução deve ser determinística para que não haja mapas de hash ou outros algoritmos estatísticos
Minha solução: Uma matriz inteligente é uma matriz de tamanho que podemos criar e "inicializar" em :
Criamos três matrizes do tamanho de sem inicializar qualquer um deles e nós também manter uma variável inteira single chamado .
A primeira matriz contém os dados. A segunda matriz contém ponteiros para uma célula na terceira matriz. A terceira matriz contém ponteiros para uma célula na segunda matriz. contém o número de células inicializadas até o momento.
Suponha que gostaríamos de definir o valor da célula (suponha que seja a primeira vez que o fazemos nesta célula). Em seguida, iremos para a célula na primeira matriz e a definiremos para o valor desejado.
Agora vamos para a célula na segunda matriz e configuramos para apontar para a célula na terceira matriz. Defina a célula na terceira matriz para apontar para a célula na segunda matriz. Aumente em 1.
Suponha que gostaríamos de saber se a célula é uma lixeira (isso significa que ainda precisamos definir algo para ela).
Iríamos para a célula na segunda matriz e olharíamos para o número da célula (na terceira matriz) que a célula (na segunda matriz) aponta para - nós a chamaremos de .
Se então é lixo (porque só inicializamos células até agora não é uma delas).
Se , veremos para que célula (na terceira matriz) aponta. Se não for então é lixo. Caso contrário, não é lixo
Dessa forma, podemos saber em cada etapa se inicializamos esta célula e se não inicializamos. Então, criamos e "inicializamos" uma matriz de tamanho em tempo.
O principal truque não é inicializar toda a matriz no início, mas encontrar uma maneira de saber quais células inicializamos até agora e inicializar uma célula apenas quando "olhamos" para ela. No modelo de RAM, leva tempo para criar uma matriz de qualquer tamanho sem inicializá-la.
Uma árvore de palavras da ordem m é uma generalização de um TRIE. Cada nó contém uma matriz de ponteiros para seus filhos. O tamanho da matriz é . Cada nó também contém um contador para dizer quantos conjuntos existem descritos por este nó.
Como usamos matrizes inteligentes cada vez que adicionamos uma palavra (um conjunto), são necessários apenas tempo e espaço .
fonte
Time cannot be smaller than space
true.You are cheating in some way
não segue " tempo e espaço": com , - o limite no espaço parece desnecessariamente relaxado.Respostas:
Você também pode resolver isso no tempo e no espaço :O(nlogn) O(n)
Primeiro, classifique cada palavra usando o mergesort. O tempo de execução disso será no máximo e o uso do espaço é .O(nlogn) O(n)
Em seguida, armazene todas as palavras em uma palavra. O tempo e o espaço para isso serão , se você implementar a palavra tentar corretamente. Em particular, em cada nó da árvore, você deve armazenar o conjunto de filhos como uma hashtable (não como uma matriz). Dessa maneira, o armazenamento em um nó é proporcional ao número de filhos que ele possui e a pesquisa para encontrar um filho pode ser feita no tempo . Assim, o tempo de execução desse estágio é tempo e espaço.O(n) O(1) O(n) O(n)
Por fim, leia todas as palavras do artigo. Isso envolve pegar cada hashtable e classificar seu conteúdo, por exemplo, usando o mergesort. Todas essas etapas de classificação levarão no máximo .O(nlogn)
A estrutura de dados resultante parece bastante simples. É especialmente simples se você implementar em uma linguagem que tenha suporte embutido para hashmaps (por exemplo, Javascript, Python).
Como alternativa, você pode substituir o hashmap por uma estrutura de dados da árvore binária balanceada e obter um tempo de execução semelhante.
Como uma observação geral sobre "matrizes inteligentes":
Você pode substituir o uso de "matrizes inteligentes" por uma hashtable. Dessa forma, você preservará a capacidade de realizar leituras e gravações de tempo (esperado). Em particular, em vez de definir , você armazena o valor na chave (por exemplo, adicione o mapeamento à hashtable). Quando você quiser ler o valor de , procure na hashtable e retorne o que encontrar lá. Dessa maneira, o uso do espaço é proporcional ao número de entradas inicializadas na "matriz inteligente" e cada acesso leva o tempo (esperado).O(1) A[i]:=v v k k↦v A[i] i O(1)
fonte
Aqui está uma solução que não usa tabelas de hash.
Deixe ser comprimento do prefixo curto da cadeia que a distingue das outras cordas em . O prefixo distintivo de é definido como .ds s∈S S S d=∑s∈Sds
O algoritmo para resolver o problema usa uma abordagem de dividir e conquistar, é um RadixSort que começa no dígito mais significativo (char).
Esse algoritmo gera uma série -ary, na qual cada nó é uma matriz do tamanho e as seqüências são armazenadas nas folhas.σ σ
Aqui está um exemplo.
Vamos ser e .σ 5 S={410,013,042,111,001,444}
A seguir, é apresentado o trie gerado pelo algoritmo:
Cada string indica um caminho de tamanho antes que o nó que aponta para seja criado. Cada nó desses caminhos leva espaço e tempo para ser alocado.s O(ds) s O(σ) O(σ)
fonte