Me dieron este problema en una entrevista. ¿Cómo habrías respondido?
Diseñe una estructura de datos que ofrezca las siguientes operaciones en O (1) tiempo:
- insertar
- eliminar
- contiene
- obtener elemento aleatorio
data-structures
gremio
fuente
fuente
Respuestas:
Considere una estructura de datos compuesta por una tabla hash H y una matriz A. Las claves de la tabla hash son los elementos de la estructura de datos y los valores son sus posiciones en la matriz.
dado que la matriz necesita aumentar automáticamente de tamaño, se amortizará O (1) para agregar un elemento, pero supongo que está bien.
fuente
La búsqueda de O (1) implica una estructura de datos hash .
En comparación:
fuente
hashtable.get((int)(Math.random()*hashtable.size()));
Puede que esto no le guste, porque probablemente estén buscando una solución inteligente, pero a veces vale la pena ceñirse a sus armas ... Una tabla hash ya satisface los requisitos , probablemente mejor en general que cualquier otra cosa (aunque obviamente en constante amortizada tiempo, y con compromisos diferentes a otras soluciones).
El requisito que es complicado es la selección del "elemento aleatorio": en una tabla hash, necesitaría escanear o sondear dicho elemento.
Para el hash cerrado / direccionamiento abierto, la posibilidad de que se ocupe un cubo determinado es
size() / capacity()
, pero lo más importante es que esto se mantiene en un rango multiplicativo constante mediante una implementación de tabla hash (por ejemplo, la tabla puede mantenerse más grande que su contenido actual, por ejemplo, 1.2x a ~ 10x dependiendo del rendimiento / ajuste de la memoria). Esto significa que, en promedio, podemos esperar buscar entre 1,2 y 10 cubos, totalmente independiente del tamaño total del contenedor; amortizado O (1).Puedo imaginar dos enfoques simples (y muchos más complicados):
buscar linealmente desde un depósito aleatorio
intente cubos aleatorios repetidamente hasta que encuentre uno poblado
No es una gran solución, pero aún puede ser un mejor compromiso general que los gastos generales de memoria y rendimiento de mantener una segunda matriz de índices en todo momento.
fuente
La mejor solución es probablemente la tabla hash + matriz, es realmente rápida y determinista.
Pero la respuesta con la calificación más baja (¡solo use una tabla hash!) ¡También es excelente!
Puede que a la gente no le guste esto debido a "posibles bucles infinitos", y he visto a personas muy inteligentes que también tienen esta reacción, ¡pero está mal! Los eventos infinitamente improbables simplemente no suceden.
Suponiendo el buen comportamiento de su fuente pseudoaleatoria, que no es difícil de establecer para este comportamiento en particular, y que las tablas hash siempre están llenas al menos en un 20%, es fácil ver que:
Será Nunca suceder que getRandom () tiene que probar más de 1000 veces. Simplemente nunca . De hecho, la probabilidad de que se produzca un evento de este tipo es 0,8 ^ 1000, que es 10 ^ -97, por lo que tendríamos que repetirlo 10 ^ 88 veces para tener una posibilidad entre mil millones de que ocurra una vez. Incluso si este programa se ejecutara a tiempo completo en todas las computadoras de la humanidad hasta que el Sol muera, esto nunca sucederá.
fuente
Para esta pregunta utilizaré dos estructuras de datos
Pasos: -
Código: -
- Complejidad temporal O (1). - Complejidad espacial O (N).
fuente
Aquí hay una solución de C # para ese problema que se me ocurrió hace un tiempo cuando me hicieron la misma pregunta. Implementa Agregar, Eliminar, Contiene y Aleatorio junto con otras interfaces .NET estándar. No es que necesite implementarlo con tanto detalle durante una entrevista, pero es bueno tener una solución concreta para analizar ...
fuente
ArgumentException
con el mensaje "Ya se agregó un elemento con la misma clave". se lanzará (desde el diccionario de índice subyacente).Podemos usar hash para respaldar operaciones en Θ (1) tiempo.
insert (x) 1) Verifique si x ya está presente haciendo una búsqueda de mapa hash. 2) Si no está presente, insértelo al final de la matriz. 3) Agregue también la tabla hash, x se agrega como clave y el último índice de matriz como índice.
remove (x) 1) Verifique si x está presente haciendo una búsqueda de mapa hash. 2) Si está presente, busque su índice y elimínelo del mapa hash. 3) Cambie el último elemento con este elemento en la matriz y elimine el último elemento. El intercambio se realiza porque el último elemento se puede eliminar en O (1) tiempo. 4) Actualizar el índice del último elemento en el mapa hash.
getRandom () 1) Genera un número aleatorio desde 0 hasta el último índice. 2) Devuelve el elemento de la matriz en el índice generado aleatoriamente.
search (x) Realiza una búsqueda de x en el mapa hash.
fuente
Aunque esto es muy antiguo, pero como no hay respuesta en C ++, aquí está mi granito de arena.
Aquí hay un fragmento de código de cliente para probar la solución.
fuente
En C # 3.0 + .NET Framework 4, un genérico
Dictionary<TKey,TValue>
es incluso mejor que un Hashtable porque puede usar elSystem.Linq
método de extensiónElementAt()
para indexar en la matriz dinámica subyacente dondeKeyValuePair<TKey,TValue>
se almacenan los elementos:Sin embargo, hasta donde yo sé, una tabla hash (o su progenie del diccionario) no es una solución real a este problema porque Put () solo se puede amortizar O (1), no O (1) verdadero, porque es O (N ) en el límite de cambio de tamaño dinámico.
¿Existe una solución real a este problema? Todo lo que puedo pensar es que si especifica una capacidad inicial de Dictionary / Hashtable en un orden de magnitud más allá de lo que anticipa que necesitará, entonces obtendrá operaciones O (1) porque nunca necesita cambiar el tamaño.
fuente
Estoy de acuerdo con Anon. Excepto por el último requisito, donde se requiere obtener un elemento aleatorio con la misma imparcialidad, todos los demás requisitos se pueden abordar solo utilizando un único DS basado en Hash. Elegiré HashSet para esto en Java. El módulo de código hash de un elemento me dará el número de índice de la matriz subyacente en el tiempo O (1). Puedo usar eso para agregar, eliminar y contiene operaciones.
fuente
¿No podemos hacer esto usando HashSet of Java? Proporciona insertar, eliminar, buscar todo en O (1) de forma predeterminada. Para getRandom podemos hacer uso del iterador de Set que de todos modos da un comportamiento aleatorio. Podemos simplemente iterar el primer elemento del conjunto sin preocuparnos por el resto de los elementos
fuente
fuente
¿Por qué no usamos epoch% arraysize para encontrar un elemento aleatorio? Encontrar el tamaño de la matriz es O (n) pero la complejidad amortizada será O (1).
fuente
Creo que podemos usar doble lista de enlaces con tabla hash. la clave será elemento y su valor asociado será nodo en doble lista de enlaces.
fuente