Isto é o que eu criei, que não requer o bit de sinal adicional:
for i := 0 to n - 1
while A[A[i]] != A[i]
swap(A[i], A[A[i]])
end while
end for
for i := 0 to n - 1
if A[i] != i then
print A[i]
end if
end for
O primeiro loop permite a matriz, de modo que, se o elemento x
estiver presente pelo menos uma vez, uma dessas entradas estará na posição A[x]
.
Observe que ele pode não parecer O (n) à primeira vista, mas é - embora tenha um loop aninhado, ainda é executado no O(N)
tempo. Uma troca ocorre apenas se houver uma i
tal que A[i] != i
, e cada troca define pelo menos um elemento como A[i] == i
, onde isso não era verdade antes. Isso significa que o número total de swaps (e, portanto, o número total de execuções do while
corpo do loop) é no máximo N-1
.
O segundo loop imprime os valores dos x
quais A[x]
não é igual x
- já que o primeiro loop garante que, se x
existir pelo menos uma vez na matriz, uma dessas instâncias estará em A[x]
, isso significa que ele imprime os valores dos x
quais não estão presentes em a matriz.
(Link Ideone para que você possa brincar com ele)
a[a[i]]
, e a restrição de espaço O (1) indica que aswap()
operação é a chave.5
não está no intervalo0..N-1
(N
neste caso5
).print
instrução paraprint i
transformá-la em uma solução para stackoverflow.com/questions/5249985/… e (assumindo que "bag" seja uma matriz modificável)) Qk de stackoverflow.com/questions/3492302/… .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:
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 saberA[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 implicavaA[i]
uma duplicata. Na minha versão, confio em uma invariante ligeiramente diferente: issoA[i] != i && A[A[i]] == A[i]
implica queA[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 queA[i]
pode ser uma duplicata que não foi vista antes. Se não vimos isso antes, esperamos queA[i]
a localização da casa aponte para si mesma - é isso que é testado na segunda metade daif
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 sejai
satisfatóriaA[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ésticasm
sejam reproduzidas como duplicatas, causando aif
falha da segunda metade de suas condições, mas funcionará quandoi
chegar ao local de origemm
? Sim, sim, porque agora, embora neste novoi
achemos que a 1ª metade daif
condiçãoA[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 foim
ouA[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 sem != A[m]
exatamente um dem
eA[m]
ocorre mais de uma vez e o outro não ocorre).fonte
Aqui está o pseudocódigo
Código de exemplo em C ++
fonte
-
por~
para o problema zero.O(n)
espaço oculto - osn
bits do sinal. Se a matriz for definida de modo que cada elemento possa conter apenas valores entre0
en-1
, obviamente não funcionará.Para N relativamente pequeno, podemos usar operações div / mod
Não C / C ++, mas mesmo assim
http://ideone.com/GRZPI
fonte
Não é realmente bonito, mas pelo menos é fácil ver as propriedades O (N) e O (1). Basicamente, examinamos a matriz e, para cada número, vemos se a posição correspondente foi sinalizada já vista uma vez (N) ou já vista várias vezes (N + 1). Se estiver sinalizado já visto uma vez, imprimimos e sinalizamos já visto várias vezes. Se não estiver sinalizado, sinalizamos já visto uma vez e movemos o valor original do índice correspondente para a posição atual (sinalizar é uma operação destrutiva).
ou, melhor ainda (mais rápido, apesar do loop duplo):
fonte
if (value > i) a[i--] = a[value];
funciona: sevalue <= i
já processamos o valor ema[value]
e podemos substituí-lo com segurança. Também não diria que a natureza O (N) é óbvia! Soletrando: O loop principal executa osN
tempos, além de muitas vezes aa[i--] = a[value];
linha. Essa linha pode ser executada apenas sea[value] < N
, e toda vez que for executada, imediatamente depois, um valor de matriz que ainda não estavaN
definidoN
, para que possa ser executado na maioria dasN
vezes, para um total de no máximo2N
iterações de loop.Uma solução em C é:
É O (n) tempo e O (1) complexidade do espaço.
fonte
Vamos supor que apresentamos essa matriz como uma estrutura de dados de gráfico unidirecional - cada número é um vértice e seu índice na matriz aponta para outro vértice, formando uma aresta do gráfico.
Para ainda mais simplicidade, temos os índices 0 a n-1 e o intervalo de números de 0..n-1. por exemplo
0 (3) -> 3 (3) é um ciclo.
Resposta: Basta percorrer a matriz confiando em índices. se a [x] = a [y], então é um ciclo e, portanto, duplicado. Pule para o próximo índice e continue novamente até o final de uma matriz. Complexidade: O (n) tempo e O (1) espaço.
fonte
Um pequeno código python para demonstrar o método caf acima:
fonte
i
valor - observewhile
na minha resposta.O algoritmo pode ser facilmente visto na seguinte função C. A recuperação da matriz original, embora não seja necessária, será possível usando cada módulo de entrada n .
Ideone Link para teste.
fonte
fonte
Criei um aplicativo de playground de exemplo rapidamente para encontrar duplicatas na complexidade de tempo 0 (n) e no espaço extra constante. Por favor, verifique o URL Encontrando Duplicatas
A solução IMP Above funcionou quando uma matriz contém elementos de 0 a n-1, com qualquer um desses números aparecendo inúmeras vezes.
fonte
fonte
Se a matriz não for muito grande, essa solução é mais simples, cria outra matriz do mesmo tamanho para marcação.
1 Crie um bitmap / matriz do mesmo tamanho que sua matriz de entrada
2 digitalize sua matriz de entrada e aumente sua contagem na matriz acima
3 Agora digitalize a matriz check_list e imprima a duplicata uma vez ou quantas vezes foram duplicadas
Obviamente, é necessário o dobro do espaço consumido pela solução fornecida acima, mas a eficiência do tempo é O (2n), que é basicamente O (n).
fonte
O(1)
espaço.