Me hicieron esta pregunta en una entrevista de trabajo, y me gustaría saber cómo otros la resolverían. Me siento más cómodo con Java, pero las soluciones en otros idiomas son bienvenidas.
Dada una matriz de números,
nums
devuelve una matriz de númerosproducts
, dondeproducts[i]
es el producto de todosnums[j], j != i
.Input : [1, 2, 3, 4, 5] Output: [(2*3*4*5), (1*3*4*5), (1*2*4*5), (1*2*3*5), (1*2*3*4)] = [120, 60, 40, 30, 24]
Debe hacer esto
O(N)
sin usar la división.
[interview-questions]
etiqueta buscándola. ¿Tienes un enlace si lo has encontrado?Respuestas:
Una explicación del método polygenelubricants es: El truco consiste en construir las matrices (en el caso de 4 elementos)
Ambos se pueden hacer en O (n) comenzando en los bordes izquierdo y derecho respectivamente.
Luego, multiplicar las dos matrices elemento por elemento da el resultado requerido
Mi código se vería así:
Si necesita estar O (1) en el espacio también, puede hacerlo (lo cual es menos claro en mi humilde opinión)
fuente
v_i=0
la única entrada distinta de cero en el resultado es el elemento i-ésimo. Sin embargo, sospecho que agregar un pase para detectar y contar los elementos cero disminuiría la claridad de la solución, y probablemente no generaría ningún aumento de rendimiento real en la mayoría de los casos ...Aquí hay una pequeña función recursiva (en C ++) para hacer la modificación en su lugar. Sin embargo, requiere O (n) espacio extra (en la pila). Suponiendo que la matriz está en ay N tiene la longitud de la matriz, tenemos
fuente
num[N-1]
; luego, en el camino de regreso, calcula la segunda parte de la multiplicación que luego se utiliza para modificar la matriz de números en su lugar.Aquí está mi intento de resolverlo en Java. Disculpas por el formato no estándar, pero el código tiene mucha duplicación, y esto es lo mejor que puedo hacer para que sea legible.
Los invariantes de bucle son
pi = nums[0] * nums[1] *.. nums[i-1]
ypj = nums[N-1] * nums[N-2] *.. nums[j+1]
. Lai
parte de la izquierda es la lógica del "prefijo", y laj
parte de la derecha es la lógica del "sufijo".One-liner recursivo
Jasmeet dio una (¡hermosa!) Solución recursiva; Lo he convertido en este (¡horrible!) Java de una sola línea. Realiza modificaciones en el lugar , con
O(N)
espacio temporal en la pila.fuente
Traduciendo la solución de Michael Anderson a Haskell:
fuente
Eludiendo furtivamente la regla de "sin divisiones":
fuente
Aquí tienes, solución simple y limpia con complejidad O (N):
fuente
C ++, O (n):
fuente
En)
fuente
Aquí está mi solución en C ++ moderno. Hace uso de
std::transform
y es bastante fácil de recordar.Código en línea (wandbox).
fuente
Esto es O (n ^ 2) pero f # es muuuy hermoso:
fuente
Precalcule el producto de los números a la izquierda y a la derecha de cada elemento. Para cada elemento, el valor deseado es el producto de los productos de sus vecinos.
Resultado:
(ACTUALIZACIÓN: ahora miro más de cerca, esto usa el mismo método que Michael Anderson, Daniel Migowski y polygenelubricants arriba)
fuente
Difícil:
Use lo siguiente:
Sí, estoy seguro de que me perdí algo de i-1 en lugar de i, pero esa es la manera de resolverlo.
fuente
También hay una solución no óptima O (N ^ (3/2)) . Sin embargo, es bastante interesante.
Primero preprocese cada multiplicación parcial de tamaño N ^ 0.5 (esto se hace en complejidad de tiempo O (N)). Luego, el cálculo para el múltiplo de otros valores de cada número se puede hacer en 2 * O (N ^ 0.5) tiempo (¿por qué? Porque solo necesita multiplicar los últimos elementos de otros ((N ^ 0.5) - 1) números, y multiplique el resultado con ((N ^ 0.5) - 1) números que pertenecen al grupo del número actual). Al hacer esto para cada número, se puede obtener el tiempo O (N ^ (3/2)).
Ejemplo:
4 6 7 2 3 1 9 5 8
resultados parciales: 4 * 6 * 7 = 168 2 * 3 * 1 = 6 9 * 5 * 8 = 360
Para calcular el valor de 3, uno necesita multiplicar los valores de los otros grupos 168 * 360, y luego con 2 * 1.
fuente
Se me ocurrió esta solución y la encontré tan clara ¿qué te parece?
fuente
arr = [1, 2, 3, 4, 5] prod = [] productify (arr, prod, 0) print prod
fuente
Para completar aquí está el código en Scala:
Esto imprimirá lo siguiente:
El programa filtrará el elemento actual (_! = Elem); y multiplique la nueva lista con el método reduceLeft. Creo que esto será O (n) si usa la vista de escala o Iterator para la evaluación diferida.
fuente
Basado en la respuesta de Billz: lo siento, no puedo comentar, pero aquí hay una versión scala que maneja correctamente los elementos duplicados en la lista, y probablemente sea O (n):
devoluciones:
fuente
Agregué mi solución de JavaScript aquí ya que no encontré a nadie sugiriendo esto. ¿Qué es dividir, excepto contar la cantidad de veces que puede extraer un número de otro número? Pasé por calcular el producto de toda la matriz, y luego iterar sobre cada elemento y restar el elemento actual hasta cero:
fuente
Estoy acostumbrado a C #:
fuente
Podemos excluir el
nums[j]
(dóndej != i
) de la lista primero, luego obtener el producto del resto; Lo siguiente espython way
para resolver este rompecabezas:fuente
Bueno, esta solución puede considerarse la de C / C ++. Digamos que tenemos una matriz "a" que contiene n elementos como a [n], entonces el pseudocódigo sería el siguiente.
fuente
Una solución más, usando la división. con doble recorrido. Multiplique todos los elementos y luego comience a dividirlo por cada elemento.
fuente
fuente
Aquí está mi código:
fuente
Aquí hay un ejemplo ligeramente funcional, usando C #:
No estoy completamente seguro de que esto sea O (n), debido a la semi-recursión de los Funcs creados, pero mis pruebas parecen indicar que es O (n) a tiempo.
fuente
// Esta es la solución recursiva en Java // Llamada de la siguiente manera desde el producto principal (a, 1,0);
fuente
Una solución ordenada con O (n) tiempo de ejecución:
Cree un "resultado" de matriz final, para un elemento i,
fuente
fuente
Aquí hay otro concepto simple que resuelve el problema
O(N)
.fuente
Tengo una solución con
O(n)
laO(n^2)
complejidad de espacio y tiempo que se proporciona a continuación,fuente