reduzir Permutation
-
20-08-2019 - |
Pergunta
Eu preciso de um algoritmo que pode mapear as corridas em uma permutação a um único número, mas também reduzir os números subseqüentes.
Assim, uma corrida é um conjunto sequencial de números em uma permutação que é ordenada e em ordem. Na lista, 1; 2; 3; 5; 6; 4 existem duas pistas, 1; 2; 3 e 5; 6. Quero substituir estes com um único número, no mínimo, por isso, se, após a remoção de corridas, temos uma permutação de 4 elementos, a permutação usa os números 1 ... 4. No exemplo acima, temos de reduzir as duas corridas . a primeira execução seria uma, 4 transforma a 2, e [5; 6] transforma a 3, para segurar o segundo critério. Se eu meio a permutação reduzida em seguida, expanda os elementos dentro do mapeamento e classificar a permutação original eu obterá o mesmo resultado. A permutação resultante não deve ter nenhum corre na mesma.
Por exemplo, (i você destacou as corridas):
(1;2;3;4;5;6) => 1 //Mappings: 1->1;2;3;4;5;6
(2;3;4);1;(5;6) => 2 1 3 // Mappings: 2->2;3;4, and 3->5;6
(3;4);(1;2);(5;6) => 2 1 3 // Mappings: 2->3;4, and 1->1;2 and 3->5;6
Por enquanto, eu estou passando sobre a lista e fazer uma lista de listas, agrupando as pistas. Realmente a segunda parte é a parte mais difícil de fazer uma solução limpa. Tenho pensado da abordagem ingênua, curioso, se alguém tem algum truque inteligente que pode fazê-lo melhor, então a minha, eu estou em como O (2n + n log n),
- substituindo as corridas com o elemento de cabeça da corrida e inserir esses dados em uma tabela hash (para recuperação)
- triagem para criar um mapa para os dígitos que faltam com ele do índice ordenado. [1; 6; 5; 4] saída seria [(1,1); (4,2); (5,3); (6,4)]
- substituindo a lista no passo 1 com o mapa criado no passo 2 e atualizar o hashtable para a tradução.
correndo através de um novo exemplo:
step 1: replace runs with the head element of the run and inserting data into a hash table [1;3;4;2;5;6;] -> [1;3;2;5] step 2: sort array to create map [1235], so we know that, in the previous array, 1 maps to 1, 2 to 2, 3 to 3, 4 to 5. step 3: do above translation on array from step one. [1;3;2;4]
Se este tipo de permutação e reconstruir: [1; 2; 3; 4], 3-> 3; 4 e 4-> 5; 6 fico, 1; 2; 3; 4; 5; 6. Também classificada.
Eu estou usando listas, então uma abordagem funcional seria preferível. Nenhum código necessário. Todas as ideias, naturalmente, bem-vindos.
EDIT:
mweerden:
Não está claro para mim o que as condições precisas sobre o mapeamento é. Por que exatamente não é permitido apenas para produzir a permutação [1,2, ..., N] para uma permutação com corridas N? Você parecem preferir para mapear uma corrida para um número a partir desse prazo, mas (como isso nem sempre é possível) você parecem permitir alguma liberdade. -
Eu não preferem para mapear uma corrida para um número dentro desse prazo (olhar acima!), Mas eu preciso para preservar um ordenação . A permutação [1; 2; 3 ... N] é um prazo, e, assim, pode ser mais reduzido. É por isso que é inválido. A ordem importa em outras operações em outro algoritmo, mas os elementos individuais podem ser expandidas no fim de resgatar a permutação originais.
Solução
Notação:
- A contagem começa em 1
-
l.i
é elementoi
da listal
-
l+m
é a concatenação de listasl
em
- uma corrida é uma sublista máxima que é uma
[n,n+1,n+2,...,m]
lista por algumn
em
comn <= m
Por isso, estamos dado um p
permutação da lista [1,2,...,N]
. Dividimos p
-se em corridas r_1,r_2,...,r_M
tal que p = r_1+r_2+...+r_M
. Estamos, então, à procura de um q
permutação de [1,2,...,M]
tal que r_(q.1)+r_(q.2)+...+r_(q.M) = [1,2,...,N]
.
Por exemplo, se p = [1,3,4,2,5,6]
, temos N=6
, M=4
, r_1 = [1]
, r_2 = [3,4]
, r_3 = [2]
e r_4 = [5,6]
. Neste caso, precisamos q
ser [1,3,2,4]
como r_1+r_3+r_2+r_4 = [1]+[2]+[3,4]+[5,6] = [1,2,3,4,5,6]
.
Note que q
não pode conter corridas de maior comprimento de um por definição; Se fosse, então não é um i < M
com q.i + 1 = q.(i+1)
e, portanto, uma r_(q.i)+r_(q.(i+1)) = r_(q.i)+r_(q.i + 1)
sublista de [1,2,...,N]
, mas r_(q.i)+r_(q.i + 1)
também é uma sublista de p
que contradiz que r_(q.i)
e r_(q.i + 1)
são corridas.
Agora, para encontrar um q
dado um p
, assumimos a disponibilidade de uma estrutura de dados de mapeamento com inserções O(1)
e pesquisas de números e listas com Anexa O(1)
e travessia para a frente. Em seguida, faça o seguinte.
-
Em primeiro lugar, construir a lista
runheads = [r_1.1,r_2.1,...,r_M.1]
. Isso pode ser feito trivialmente porp
travessia, mantendo a execução atual. Durante esta etapa, nós também lembrar o número máximo encontrado para obterN
no final e construir umheads
mapeamento com os elementos darunheads
como chaves. Esta etapa é claramenteO(n)
. Note que não é relevante que os valores deheads
são, para que possamos usar apenasr_i
executado como valor parar_i.1
chave. -
Em seguida, iterate de
1
até (e incluindo)N
manter umk
valor com1
valor inicial. Para cadai
valor que verificar para ver sei
está emheads
. Se este for o caso, adicionari -> k
a umf
mapeamento e aumentok
. Esta etapa também é claramenteO(n)
. Para ser capaz de voltar deq
parap
também pode armazenar umrev
mapeamento adicional comk -> i
ou mesmok -> runheads(i)
, sem nenhum custo big-O extra. -
Finalmente, aplicar o mapeamento
f
aos elementos darunheads
para obterq
. NovamenteO(n)
.
Para ilustrar com um exemplo olharmos para o caso que p = [1,3,4,2,5,6]
.
-
Na primeira etapa temos
runheads = [1,3,2,5]
,N=6
eheads = { 1 -> [1], 3 -> [3,4], 2 -> [2], 5 -> [5,6] }
. -
Para o segundo passos que quatro casos para os quais temos de fazer alguma coisa:
1
,2
,3
e5
. Para esses casos, temos valores parak
que são1
,2
,3
e4
, respectivamente. Isto significa quef
será{ 1 -> 1, 2 -> 2, 3 -> 3, 5 -> 4 }
. (Erev
seria{ 1 -> 1, 2 -> 2, 3 -> 3, 4 -> 5 }
ou{ 1 -> [1], 2 -> [2], 3 -> [3,4], 4 -> [5,6] }
, dependendo do que você escolheu a loja.) -
Para obter
q
calculamosmap(f,runheads)
que é[f(1),f(3),f(2),f(5)]
ou, equivalente,[1,3,2,4]
.
Então, se eu não cometer um erroe se as estruturas de dados satisfazem os requisitos acima, esta solução deve ser O(n)
. Note-se que, na prática, pode realmente ser mais útil para usar sua própria solução (O(n*log(n))
). Se você tem um grande p
mas com apenas um par de corridas, classificação runheads
e usar isso para construir os mapeamentos pode ser mais eficiente. Eu acho que p
teria que ser muito grande para que este seja o caso.
Outras dicas
editado para clarificaton
passo 1: Executar o algoritmo, mas em vez de produzir apenas uma tabela hash produzir uma tabela de Hash (D1) indexados pela cabeça do conjunto é o mapeamento a (por exemplo, para [3,4] que irá ser 3) e uma lista (L1) com o próprio
set[3; 4; 6; 8; 1; 2]:
D1 L1
3 -> [3,4] 1 -> [3,4]
6 -> [6] 2 -> [6]
8 -> [8] 3 -> [8]
1 -> [1,2] 4 -> [1,2]
Passo 2: I você olhar para as coleções que temos agora, você verá que, para um dado conjunto temos o índice em que descobrimos que (em L1) eo valor Head. O valor mapa correto será o inteiro mínima entre eles que não é já tomadas. Por exemplo, para o [3,4] teremos que o valor deve ser entre 1 e 3, e, desde 1 já está tomada, o valor correspondente é 2. Leve em conta que, como D1 é indexado pelo Chefe valor, valores inferiores será sempre tomar se o conjunto correspondente existe. No exemplo, [1,2] é mapeado para 1, de modo que esta chave já está "tomadas". Assim, em pseudo-código:
for (int Current = 1; Current < L1.Length; Current++)
{
GetHead(L1[Current]);
Index = Current;
While Head > Index
{
if D1.Empty(Index)
{
D1.Add(Index,D2[Current])
D1.DeleteIfNotEmpty(Head);
}
else
Index++;
}
}
Por exemplo
- tomamos o primeiro valor em L1 -> [3,4] ...
- obter a cabeça = 3
- A partir do dia 1 nós lookup D1 [1], que já está tomada, de modo que incrementar a 2.
- Procuramos D1 [2] que é vazio, então vamos atribuir D1 [2] = [3,4] e D de exclusão [3]
Isso não fornece O (n), mas algo como O (n + log (n)) (n para a primeira etapa, log (n) para o segundo)
Para o exemplo acima que você fica:
1 -> [1,2]
2 -> [3,4]
3 -> [6]
4 -> [8]
Agora, se você tem [3; 4; 8; 6; 1; 2], que irá resultar em
1 -> [1,2]
2 -> [3,4]
3 -> [8]
4 -> [6]
porque é usando ordenação absoluta na matriz original, eu não sei se isso é certo ou você vai querer 6 para ser no índice 3 e 8 para ser no índice 4, nesse caso, você provavelmente teve para pré-venda L1 com base na cabeça que irá incrementar a sua complexidade, Log (n)
Se você tem que pré-encomenda você terá 0 (n + log ^ 2 (n)), que não é tão ruim (talvez menos assumindo uma QuickSort tem O (log n) encomendar L1 será O (log (log n))