Obtuve este problema de una entrevista con Microsoft.
Dada una matriz de enteros aleatorios, escriba un algoritmo en C que elimine los números duplicados y devuelva los números únicos en la matriz original.
Por ejemplo, entrada: {4, 8, 4, 1, 1, 2, 9}
salida:{4, 8, 1, 2, 9, ?, ?}
Una advertencia es que el algoritmo esperado no debería requerir que la matriz se ordene primero. Y cuando se ha eliminado un elemento, los siguientes elementos también deben desplazarse hacia adelante. De todos modos, el valor de los elementos en la cola de la matriz donde los elementos se desplazaron hacia adelante es insignificante.
Actualización: el resultado debe devolverse en la matriz original y la estructura de datos auxiliar (por ejemplo, tabla hash) no debe utilizarse. Sin embargo, supongo que la conservación del pedido no es necesaria.
Actualización 2: Para aquellos que se preguntan por qué estas limitaciones poco prácticas, esta fue una pregunta de entrevista y todas estas limitaciones se discuten durante el proceso de pensamiento para ver cómo puedo proponer diferentes ideas.
fuente
Respuestas:
Qué tal si:
Debe ser O (n ^ 2) o menos.
fuente
Una solución sugerida por mi novia es una variación del tipo de fusión. La única modificación es que durante el paso de combinación, simplemente ignore los valores duplicados. Esta solución también sería O (n log n). En este enfoque, la eliminación de la clasificación / duplicación se combinan. Sin embargo, no estoy seguro de si eso hace alguna diferencia.
fuente
Publiqué esto una vez antes en SO, pero lo reproduciré aquí porque es bastante bueno. Utiliza hash, construyendo algo así como un hash establecido en su lugar. Se garantiza que es O (1) en el espacio axilar (la recursividad es una llamada de cola) y, por lo general, es una complejidad de tiempo O (N). El algoritmo es como sigue:
Se puede demostrar que es O (N) siempre que no haya un escenario patológico en el hash: incluso si no hay duplicados, aproximadamente 2/3 de los elementos se eliminarán en cada recursión. Cada nivel de recursividad es O (n) donde n pequeña es la cantidad de elementos que quedan. El único problema es que, en la práctica, es más lento que una clasificación rápida cuando hay pocos duplicados, es decir, muchas colisiones. Sin embargo, cuando hay una gran cantidad de duplicados, es increíblemente rápido.
Editar: en las implementaciones actuales de D, hash_t es de 32 bits. Todo sobre este algoritmo asume que habrá muy pocas, si es que hay alguna, colisiones hash en el espacio completo de 32 bits. Sin embargo, las colisiones pueden ocurrir con frecuencia en el espacio del módulo. Sin embargo, esta suposición será, con toda probabilidad, cierta para cualquier conjunto de datos de tamaño razonable. Si la clave es menor o igual a 32 bits, puede ser su propio hash, lo que significa que una colisión en el espacio completo de 32 bits es imposible. Si es más grande, simplemente no puede colocar suficientes en el espacio de direcciones de memoria de 32 bits para que sea un problema. Supongo que hash_t aumentará a 64 bits en implementaciones de 64 bits de D, donde los conjuntos de datos pueden ser más grandes. Además, si esto llegara a ser un problema, se podría cambiar la función hash en cada nivel de recursividad.
Aquí hay una implementación en el lenguaje de programación D:
fuente
Una implementación más eficiente
En esta implementación, no es necesario ordenar la matriz. Además, si se encuentra un elemento duplicado, no es necesario desplazar todos los elementos después de esto en una posición.
La salida de este código es una matriz [] con tamaño NewLength
Aquí estamos comenzando desde el segundo elemento de la matriz y comparándolo con todos los elementos de la matriz hasta esta matriz. Tenemos una variable de índice adicional 'NewLength' para modificar la matriz de entrada. NewLength variabel se inicializa en 0.
El elemento de la matriz [1] se comparará con la matriz [0]. Si son diferentes, el valor de la matriz [NewLength] se modificará con la matriz [1] y se incrementará NewLength. Si son iguales, NewLength no se modificará.
Entonces, si tenemos una matriz [1 2 1 3 1], entonces
En el primer paso del bucle 'j', la matriz [1] (2) se comparará con la matriz0, luego 2 se escribirán en la matriz [NewLength] = matriz [1], por lo que la matriz será [1 2] ya que NewLength = 2
En la segunda pasada del bucle 'j', la matriz [2] (1) se comparará con la matriz0 y la matriz1. Aquí, dado que matriz [2] (1) y matriz0 son el mismo bucle, se romperá aquí. por lo que la matriz será [1 2] ya que NewLength = 2
y así
fuente
Si está buscando la notación O superior, ordenar la matriz con una clasificación O (n log n) y luego hacer un recorrido O (n) puede ser la mejor ruta. Sin ordenar, está mirando O (n ^ 2).
Editar: si solo está haciendo números enteros, también puede hacer una ordenación por radix para obtener O (n).
fuente
1. Utilizando O (1) espacio adicional, en O (n log n) tiempo
Esto es posible, por ejemplo:
Creo que el socio de ejel tiene razón en que la mejor manera de hacer esto sería una ordenación de combinación en el lugar con un paso de combinación simplificado, y que esa es probablemente la intención de la pregunta, si fuera por ejemplo. escribir una nueva función de biblioteca para hacer esto de la manera más eficiente posible sin la capacidad de mejorar las entradas, y habría casos en que sería útil hacerlo sin una tabla hash, dependiendo del tipo de entradas. Pero en realidad no he comprobado esto.
2. Utilizando O (lotes) de espacio extra, en O (n) tiempo
Esto solo funciona si se cumplen varias suposiciones cuestionables:
Es una mala respuesta, pero si tiene MUCHOS elementos de entrada, pero todos son enteros de 8 bits (o tal vez incluso enteros de 16 bits), podría ser la mejor manera.
3. O (poco) -espacio extra, O (n) -espacio
Como # 2, pero use una tabla hash.
4. El camino claro
Si el número de elementos es pequeño, escribir un algoritmo apropiado no es útil si otro código es más rápido de escribir y más rápido de leer.
P.ej. Camine por la matriz para cada elemento único (es decir, el primer elemento, el segundo elemento (se han eliminado los duplicados del primero), etc.) eliminando todos los elementos idénticos. O (1) espacio extra, O (n ^ 2) tiempo.
P.ej. Utilice funciones de biblioteca que hagan esto. La eficiencia depende de la que tenga fácilmente disponible.
fuente
Bueno, su implementación básica es bastante simple. Revise todos los elementos, verifique si hay duplicados en los restantes y cambie el resto sobre ellos.
Es terriblemente ineficiente y podría acelerarlo mediante una matriz auxiliar para la salida o la clasificación / árboles binarios, pero esto no parece estar permitido.
fuente
Si se le permite usar C ++, una llamada a
std::sort
seguida de una llamada astd::unique
le dará la respuesta. La complejidad de tiempo es O (N log N) para la ordenación y O (N) para el recorrido único.Y si C ++ está fuera de la mesa, no hay nada que impida que estos mismos algoritmos se escriban en C.
fuente
Puede hacer esto en un solo recorrido, si está dispuesto a sacrificar la memoria. Simplemente puede contar si ha visto un número entero o no en una matriz hash / asociativa. Si ya ha visto un número, elimínelo sobre la marcha o, mejor aún, mueva los números que no ha visto a una nueva matriz, evitando cualquier cambio en la matriz original.
En Perl:
fuente
El valor de retorno de la función debe ser el número de elementos únicos y todos están almacenados al principio de la matriz. Sin esta información adicional, ni siquiera sabrá si hubo duplicados.
Cada iteración del ciclo externo procesa un elemento de la matriz. Si es único, permanece al principio de la matriz y si es un duplicado, el último elemento sin procesar de la matriz lo sobrescribe. Esta solución se ejecuta en tiempo O (n ^ 2).
fuente
Aquí hay una versión de Java.
fuente
Aquí está mi solución.
fuente
Obviamente, una matriz debe "atravesarse" de derecha a izquierda para evitar la copia innecesaria de valores de un lado a otro.
Si tiene memoria ilimitada, puede asignar una matriz de bits por
sizeof(type-of-element-in-array) / 8
bytes para que cada bit signifique si ya ha encontrado el valor correspondiente o no.Si no lo hace, no puedo pensar en nada mejor que atravesar una matriz y comparar cada valor con los valores que le siguen y luego, si se encuentra un duplicado, eliminar estos valores por completo. Esto está en algún lugar cerca de O (n ^ 2) (o O ((n ^ 2-n) / 2) ).
IBM tiene un artículo sobre un tema cercano.
fuente
Veamos:
fuente
Esto se puede hacer en una pasada con un algoritmo O (N log N) y sin almacenamiento adicional.
Proceda del elemento
a[1]
ala[N]
. En cada etapai
, todos los elementos a la izquierda dea[i]
comprender un montón ordenada de elementosa[0]
a través dea[j]
. Mientras tanto, un segundo índicej
, inicialmente 0, realiza un seguimiento del tamaño del montón.Examínelo
a[i]
e insértelo en el montón, que ahora ocupa elementosa[0]
paraa[j+1]
. A medida que se inserta el elemento, sia[k]
se encuentra un elemento duplicado que tiene el mismo valor, no insertea[i]
en el montón (es decir, lo descarte); de lo contrario la inserta en la pila, que ahora crece por un elemento y ahora comprendea[0]
aa[j+1]
, y el incrementoj
.Continúe de esta manera, aumentando
i
hasta que todos los elementos de la matriz hayan sido examinados e insertados en el montón, que termina ocupandoa[0]
toa[j]
.j
es el índice del último elemento del montón, y el montón contiene solo valores de elementos únicos.Mirando el ejemplo, esto no es exactamente lo que se pidió, ya que la matriz resultante conserva el orden original de los elementos. Pero si este requisito se relaja, el algoritmo anterior debería funcionar.
fuente
En Java lo resolvería así. No sé cómo escribir esto en C.
fuente
¿Qué tal lo siguiente?
Intento declarar una matriz temporal y poner los elementos en ella antes de copiar todo a la matriz original.
fuente
Después de revisar el problema, aquí está mi estilo Delphi, que puede ayudar
fuente
El siguiente ejemplo debería resolver su problema:
fuente
fuente
Esta es la solución ingenua (N * (N-1) / 2). Utiliza espacio adicional constante y mantiene el orden original. Es similar a la solución de @Byju, pero no usa
if(){}
bloques. También evita copiar un elemento sobre sí mismo.fuente
Esto se puede hacer en una sola pasada, en O (N) tiempo en el número de enteros en la lista de entrada, y O (N) almacenamiento en el número de enteros únicos.
Recorra la lista de adelante hacia atrás, con dos punteros "dst" y "src" inicializados en el primer elemento. Comience con una tabla hash vacía de "enteros vistos". Si el entero en src no está presente en el hash, escríbalo en la ranura en dst e incremente dst. Agregue el entero en src al hash, luego incremente src. Repita hasta que src pase el final de la lista de entrada.
fuente
Inserte todos los elementos en un
binary tree the disregards duplicates
-O(nlog(n))
. Luego, extráigalos todos en la matriz haciendo un recorrido -O(n)
. Supongo que no necesita la conservación del pedido.fuente
Utilice un filtro de floración para hacer hash. Esto reducirá significativamente la sobrecarga de memoria.
fuente
En JAVA,
salida: {1, 2, 3, 4, 6, 7, 8, 9, 10}
espero que esto ayude
fuente
arrayInteger = {100,10,1};
Cree un
BinarySearchTree
que tenga complejidad O (n).fuente
Primero, debe crear una matriz
check[n]
donde n es el número de elementos de la matriz que desea hacer sin duplicados y establecer el valor de cada elemento (de la matriz de verificación) igual a 1. Usando un bucle for, recorra la matriz con el duplicados, digamos que su nombre esarr
, y en el bucle for escriba esto:Con eso, estableces cada duplicado igual a cero. Entonces, lo único que queda por hacer es atravesar la
arr
matriz e imprimir todo lo que no sea igual a cero. El orden permanece y toma tiempo lineal (3 * n).fuente
Dada una matriz de n elementos, escriba un algoritmo para eliminar todos los duplicados de la matriz en el tiempo O (nlogn)
En otro de los elementos se mantiene en la matriz de salida utilizando la 'clave'. Considere que la clave tiene una longitud O (n), el tiempo necesario para realizar la clasificación en la clave y el valor es O (nlogn). Entonces, el tiempo necesario para eliminar todos los duplicados de la matriz es O (nlogn).
fuente
helper data structure (e.g. hashtable) should not be used
?esto es lo que tengo, aunque pierde el orden que podemos ordenar en forma ascendente o descendente para arreglarlo.
fuente
Sería genial si tuviera una buena estructura de datos que pudiera decir rápidamente si contiene un número entero. Quizás un árbol de algún tipo.
fuente