A resposta brilhante do caf imprime cada número que aparece k vezes na matriz k-1 vezes. Esse é um comportamento útil, mas é indiscutível que a questão exige que cada duplicado seja impresso apenas uma vez, e ele alude à possibilidade de fazer isso sem soprar os limites lineares de tempo / espaço constante. Isso pode ser feito substituindo seu segundo loop pelo seguinte pseudocódigo:
for (i = 0; i < N; ++i) {
if (A[i] != i && A[A[i]] == A[i]) {
print A[i];
A[A[i]] = i;
}
}
Isso explora a propriedade que após a execução do primeiro loop, se algum valor m
aparecer mais de uma vez, é garantido que uma dessas aparências esteja na posição correta, a saber A[m]
. Se tomarmos cuidado, podemos usar esse local "residencial" para armazenar informações sobre se alguma duplicata foi impressa ou não.
Na versão caf, conforme examinamos a matriz, A[i] != i
isso implicava A[i]
uma duplicata. Na minha versão, confio em uma invariante ligeiramente diferente: isso A[i] != i && A[A[i]] == A[i]
implica que A[i]
é uma duplicata que não vimos antes . (Se você soltar a parte "que não vimos antes"), o resto poderá ser implícito na verdade invariável do caf e na garantia de que todas as duplicatas têm uma cópia em um local residencial. o início (após o 1º loop do caf terminar) e mostro abaixo que ele é mantido após cada etapa.
À medida que avançamos na matriz, o sucesso por A[i] != i
parte do teste implica que A[i]
pode ser uma duplicata que não foi vista antes. Se não vimos isso antes, esperamos que A[i]
a localização da casa aponte para si mesma - é isso que é testado na segunda metade da if
condição. Se for esse o caso, imprimimos e alteramos o local da residência para apontar para essa primeira duplicata encontrada, criando um "ciclo" em duas etapas.
Para ver que essa operação não altera nossa invariante, suponha m = A[i]
que uma determinada posição seja i
satisfatória A[i] != i && A[A[i]] == A[i]
. É óbvio que a alteração que fazemos ( A[A[i]] = i
) funcionará para impedir que outras ocorrências não domésticas m
sejam reproduzidas como duplicatas, causando a if
falha da segunda metade de suas condições, mas funcionará quando i
chegar ao local de origem m
? Sim, sim, porque agora, embora neste novo i
achemos que a 1ª metade da if
condição A[i] != i
é verdadeira, a 2ª metade testa se o local para o qual aponta é um local de origem e acha que não é. Nessa situação, não sabemos mais se foi m
ou A[m]
não o valor duplicado, mas sabemos que, de qualquer maneira,já foi relatado , porque esses 2 ciclos garantem que não apareçam no resultado do 1º loop do caf. (Observe que se m != A[m]
exatamente um de m
e A[m]
ocorre mais de uma vez e o outro não ocorre).
a[a[i]]
, e a restrição de espaço O (1) indica que aswap()
operação é a chave.