Dada una matriz NxN con 0s y 1s. Establezca cada fila que contenga a 0
para todos los 0
s y configure cada columna que contenga a 0
para todos los 0
s.
Por ejemplo
1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1
1 1 1 1 1
resultados en
0 0 0 0 0
0 0 0 0 0
0 0 1 1 0
0 0 0 0 0
0 0 1 1 0
Un ingeniero de Microsoft me dijo que hay una solución que no requiere memoria adicional, solo dos variables booleanas y una pasada, así que estoy buscando esa respuesta.
Por cierto, imagine que es una matriz de bits, por lo tanto, solo se permiten 1s y 0s en la matriz.
algorithm
optimization
puzzle
jaircazarin-old-account
fuente
fuente
Respuestas:
Ok, entonces estoy cansado ya que son las 3 AM aquí, pero tengo un primer intento en el lugar con exactamente 2 pases en cada número en la matriz, entonces en O (NxN) y es lineal en el tamaño de la matriz.
Utilizo la primera columna y la primera fila como marcadores para saber dónde están las filas / columnas con solo 1. Entonces, hay 2 variables l y c para recordar si la primera fila / columna también son todas de 1. Entonces, el primer pase establece los marcadores y restablece el resto a 0.
El segundo pase establece 1 en lugares donde las filas y los puntos están marcados como 1, y restablece la primera línea / punto dependiendo de l y c.
Dudo mucho que pueda hacerse en 1 pasada ya que los cuadrados al principio dependen de los cuadrados al final. Tal vez mi segundo pase se puede hacer más eficiente ...
fuente
Esto no se puede hacer en una pasada ya que un solo bit tiene un efecto en los bits antes y después en cualquier orden. IOW Independientemente del orden en el que atravieses la matriz, es posible que luego encuentres un 0, lo que significa que tienes que regresar y cambiar un 1 anterior a 0.
Actualizar
La gente parece pensar que al restringir N a un valor fijo (digamos 8) puede resolver esto es una pasada. Bueno, eso es a) perder el punto yb) no la pregunta original. No publicaría una pregunta sobre la clasificación y esperaría una respuesta que comenzara "suponiendo que solo desee ordenar 8 cosas ...".
Dicho esto, es un enfoque razonable si sabe que N de hecho está restringido a 8. Mi respuesta anterior responde a la pregunta original que no tiene esa restricción.
fuente
Entonces, mi idea es usar los valores en la última fila / columna como un indicador para indicar si todos los valores en la columna / fila correspondiente son 1s.
Usando un escaneo Zig Zag través de toda la matriz, EXCEPTO la fila / columna final. En cada elemento, establece el valor en la fila / columna final en cuanto al AND lógico de sí mismo con el valor en el elemento actual. En otras palabras, si golpea un 0, la fila / columna final se establecerá en 0. Si es un 1, el valor en la fila / columna final será 1 solo si ya era 1. En cualquier caso, establezca el elemento actual en 0.
Cuando haya terminado, su fila / columna final debería tener 1s si la columna / fila correspondiente se llenó con 1s.
Haga un escaneo lineal a través de la última fila y columna y busque 1s. Establezca 1s en los elementos correspondientes en el cuerpo de la matriz donde la fila final y la columna son ambos 1s.
La codificación será difícil de evitar errores, etc., pero debería funcionar de una sola vez.
fuente
Tengo una solución aquí, se ejecuta en una sola pasada, y todo el procesamiento "en su lugar" sin memoria adicional (salvo para aumentar la pila).
Utiliza la recursividad para retrasar la escritura de ceros que, por supuesto, destruiría la matriz para las otras filas y columnas:
fuente
No creo que sea factible. Cuando estás en el primer cuadrado y su valor es 1, no tienes forma de saber cuáles son los valores de los otros cuadrados en la misma fila y columna. Por lo tanto, debe verificarlos y, si hay un cero, volver al primer cuadrado y cambiar su valor a cero. Recomendaré hacerlo en dos pasos: el primer paso recopila información sobre qué filas y columnas se deben poner a cero (la información se almacena en una matriz, por lo que estamos usando algo de memoria adicional). La segunda pasada cambia los valores. Sé que esa no es la solución que estás buscando, pero creo que es práctica. Las restricciones dadas por usted hacen que el problema no tenga solución.
fuente
Puedo hacerlo con dos variables enteras y dos pases (hasta 32 filas y columnas ...)
fuente
~
Invierte todos los bits en una variable. 0x00000000 se convierte en 0x00000000. Básicamente empiezo con todos y borro el bit para una fila / columna cuando encuentro un 0. CompleteCols tiene los bits 2 y 3 establecidos, y CompleteRows tiene los bits 2 y 4 establecidos (basados en 0).el problema se puede resolver de una sola vez
guardar la matriz en una matriz i X j.
ahora imprima todos los valores como 0 para los valores de i y j guardados en ayb, el resto de los valores son 1, es decir (3,3) (3,4) (5,3) y (5,4)
fuente
Otra solución que requiere dos pasadas es acumular AND horizontal y verticalmente:
Pensé que podría diseñar tal algoritmo usando bits de paridad , códigos de Hamming o programación dinámica , posiblemente usando esos dos booleanos como un número de 2 bits, pero aún no he tenido éxito.
¿Puede volver a verificar la declaración del problema con su ingeniero e informarnos? Si no es de hecho una solución, quiero seguir saltando lejos en el problema.
fuente
Mantenga una sola variable para realizar un seguimiento de lo que son todas las filas AND juntas.
Si una fila es -1 (todos los 1), haga que la siguiente fila sea una referencia a esa variable
Si una fila es cualquier cosa menos, es un 0. Puede hacer todo en una sola pasada. Código Psuedo:
Eso debería hacerlo, en una sola pasada, pero aquí se supone que N es lo suficientemente pequeño como para que la CPU realice operaciones aritméticas en una sola fila, de lo contrario, tendrá que recorrer cada fila para determinar si es todo 1 o no, creo. Pero dado que está preguntando acerca de algos y no limita mi hardware, simplemente comenzaría mi respuesta con "Construir una CPU que admita aritmética de N bits ..."
Aquí hay un ejemplo de cómo se puede hacer en C. Nota Argumento que los valores y arr juntos representan la matriz, y p y numproduct son mi iterador y las variables de producto AND utilizan para implementar el problema. (Podría haber pasado por encima de arr con la aritmética de puntero para validar mi trabajo, ¡pero una vez fue suficiente!)
Esto produce 0, 0, 6, 0, 6, que es el resultado de las entradas dadas.
O en PHP, si la gente piensa que mis juegos de stack en C están engañando (te sugiero que no lo sea, porque debería poder almacenar la matriz de la forma que prefiera):
¿Me estoy perdiendo de algo?
fuente
Buen desafío. Esta solución usa solo dos booleanos creados en la pila, pero los booleanos se crean varias veces en la pila ya que la función es recursiva.
Esto escanea en un patrón como:
y así
Y luego cambiando los valores en este patrón al regresar en cada una de las funciones de escaneo. (De abajo hacia arriba):
y así
fuente
Esta es una solución que
fuente
Realmente. Si solo desea ejecutar el algoritmo e imprimir los resultados (es decir, no restaurarlos, entonces esto se puede hacer fácilmente de una sola vez. El problema surge cuando intenta modificar la matriz mientras ejecuta el algoritmo.
Aquí está mi solución. Simplemente implica ANDing los valores de filas / columnas para un elemento givein (i, j) e imprimirlo.
fuente
Traté de resolver este problema en C #.
He usado dos variables de bucle (i y j) aparte de la matriz real yn representando su dimensión
La lógica que intenté es:
Código:
fuente
One Pass: he recorrido la entrada solo una vez, pero he usado una nueva matriz y solo dos variables booleanas adicionales.
fuente
Si bien es imposible dadas las limitaciones, la forma más eficiente de hacerlo es atravesando la matriz de una manera superpuesta, alternando fila / columna, lo que haría un patrón similar a colocar ladrillos en forma de zig-zag:
Con esto, iría en cada fila / columna, como se indica, y si encuentra un 0 en cualquier momento, establezca una variable booleana y vuelva a caminar esa fila / columna, estableciendo las entradas en 0 a medida que avanza.
Esto no requerirá memoria adicional y solo usará una variable booleana. Desafortunadamente, si el borde "lejano" se establece en 0, ese es el peor de los casos y recorre todo el conjunto dos veces.
fuente
crear una matriz de resultados y establecer todos los valores en 1. ir a través de la matriz de datos tan pronto como se encuentre un 0, establecer la columna de fila de la matriz de resultados en 0
Al final de la primera pasada, la matriz de resultados tendrá la respuesta correcta.
Parece bastante simple ¿Hay algún truco que me estoy perdiendo? ¿No tienes permiso para usar un conjunto de resultados?
EDITAR:
Parece una función F #, pero eso es un poco engañoso, ya que a pesar de que está haciendo una sola pasada, la función puede ser recursiva.
Parece que el entrevistador está tratando de averiguar si conoce la programación funcional.
fuente
Bueno, se me ocurrió una solución de un solo paso, in situ (no recursiva) usando 4 bools y 2 contadores de bucle. No he logrado reducirlo a 2 bools y 2 ints, pero no me sorprendería si fuera posible. Hace alrededor de 3 lecturas y 3 escrituras de cada celda, y debe ser O (N ^ 2), es decir. lineal en el tamaño de la matriz.
Me tomó un par de horas resolver esto: ¡no quisiera tener que pensarlo bajo la presión de una entrevista! Si he hecho un booboo, estoy demasiado cansado para detectarlo ...
Um ... ¡Estoy eligiendo definir "paso único" como hacer un barrido a través de la matriz, en lugar de tocar cada valor una vez! :-)
fuente
Espero que disfrutes de mi solución C # de 1 pasada
puede recuperar un elemento con O (1) y solo necesita el espacio de una fila y una columna de la matriz
fuente
1 pase, 2 booleanos. Solo tengo que asumir que los índices enteros en las iteraciones no cuentan.
Esta no es una solución completa, pero no puedo pasar este punto.
Si solo pudiera determinar si un 0 es un 0 original o un 1 que se convirtió a 0, entonces no tendría que usar -1 y esto funcionaría.
Mi salida es así:
La originalidad de mi enfoque es usar la primera mitad del examen de una fila o columna para determinar si contiene un 0 y la última mitad para establecer los valores; esto se hace mirando x y ancho-x y luego y y altura -y en cada iteración. Según los resultados de la primera mitad de la iteración, si se encuentra un 0 en la fila o columna, utilizo la última mitad de la iteración para cambiar los 1 a -1.
Me acabo de dar cuenta de que esto podría hacerse con solo 1 booleano dejando 1 para ...?
Estoy publicando esto con la esperanza de que alguien pueda decir: "Ah, solo haz esto ..." (Y pasé demasiado tiempo para no publicar).
Aquí está el código en VB:
fuente
¿Nadie está usando formas binarias? ya que es solo 1 y 0. Podemos usar vectores binarios.
Aquí está la prueba:
Y la salida:
fuente
Puede hacer algo como esto para usar una pasada pero una matriz de entrada y salida:
donde
col(xy)
están los bits en la columna que contiene el puntoxy
;row(xy)
son los bits en la fila que contiene el puntoxy
.n
es el tamaño de la matriz.Luego, simplemente repita la entrada. ¿Posiblemente expandible para ser más eficiente en espacio?
fuente
Una exploración matricial, dos booleanos, sin recursión.
¿Cómo evitar el segundo pase? La segunda pasada es necesaria para borrar las filas o columnas cuando el cero aparece al final.
Sin embargo, este problema se puede resolver, porque cuando escaneamos la fila #i ya sabemos el estado de la fila # i-1. Entonces, mientras estamos escaneando la fila #i, podemos borrar simultáneamente la fila # i-1 si es necesario.
La misma solución funciona para columnas, pero necesitamos escanear filas y columnas simultáneamente mientras la próxima iteración no cambia los datos.
Se requieren dos booleanos para almacenar el estado de la primera fila y la primera columna, porque sus valores cambiarán durante la ejecución de la parte principal del algoritmo.
Para evitar agregar más booleanos, estamos almacenando el indicador "borrar" para las filas y columnas en la primera fila y columna de la matriz.
fuente
Parece que lo siguiente funciona sin requisitos de espacio adicionales:
primera nota que multiplicando los elementos de la fila por los elementos de la línea en la que se encuentra un elemento, da el valor deseado.
Para no usar ningún espacio adicional (no hacer una nueva matriz y llenarla, sino aplicar cambios directamente a la matriz), comience en la parte superior izquierda de la matriz y calcule cualquier matriz ixi (que "comienza" en (0 , 0)) antes de considerar cualquier elemento con cualquier índice> i.
Espero que esto funcione (no he probado)
fuente
Esto se PROBADO para diferentes N en C ++, y es:
una pasada , DOS Bools , NO RECURSION , NO memoria adicional , se mantiene para ARBITRARLY GRANDE N
(Hasta ahora ninguna de las soluciones aquí hacer todo esto.)
Más específicamente, me divierte que dos contadores de bucle estén bien. Tengo dos const sin firmar, que solo existen en lugar de ser calculados cada vez para facilitar la lectura. El intervalo del bucle externo es [0, N] y el intervalo del bucle interno es [1, n - 1]. La declaración de cambio está en el bucle sobre todo existe para mostrar muy claramente que realmente es solo una pasada.
Estrategia de algoritmo:
El primer truco es para nosotros una fila y una columna de la matriz misma para acumular el contenido de la matriz, esta memoria está disponible al descargar todo lo que realmente necesitamos saber de la primera fila y columna en dos booleanos. El segundo truco es obtener dos pases de uno, utilizando la simetría de la submatriz y sus índices.
Sinopsis del algoritmo:
Implementación de C ++ templada:
fuente
Ok, me doy cuenta de que no es un buen partido, pero lo obtuve en una pasada usando un bool y un byte en lugar de dos bools ... cerca. Tampoco respondería por la eficiencia, pero este tipo de preguntas a menudo requieren soluciones menos que óptimas.
fuente
Puede hacerlo de una sola vez, si no cuenta el acceso a la matriz en orden de acceso aleatorio, lo que elimina los beneficios de hacerlo en un solo paso en primer lugar (coherencia de caché / ancho de banda de memoria).
[editar: simple, pero se eliminó la solución incorrecta]
Debería obtener un mejor rendimiento que cualquier método de una sola pasada al hacerlo en dos pasadas: una para acumular información de fila / columna y otra para aplicarla. Se accede a la matriz (en orden de fila mayor) de manera coherente; Para las matrices que exceden el tamaño de la memoria caché (pero cuyas filas pueden caber en la memoria caché), los datos deben leerse de la memoria dos veces y almacenarse una vez:
fuente
La solución más simple que se me ocurre está pegada a continuación. La lógica es registrar qué fila y columna establecer cero mientras itera.
fuente
Aquí está mi implementación de Ruby con la prueba incluida. Esto tomaría espacio O (MN). Si queremos una actualización en tiempo real (como mostrar los resultados cuando encontramos ceros en lugar de esperar el primer ciclo de encontrar ceros), simplemente podemos crear otra variable de clase como
@output
y cada vez que encontramos un cero, actualizamos@output
y no@input
.fuente
El siguiente código crea una matriz de tamaño m, n. Primero decida las dimensiones de la matriz. Quería llenar la matriz [m] [n] al azar con números entre 0..10. Luego cree otra matriz de las mismas dimensiones y llénela con -1s (matriz final). Luego, recorra la matriz inicial para ver si alcanzará 0. Cuando llegue a la ubicación (x, y), vaya a la matriz final y complete la fila x con 0s y la columna y con 0s. Al final, lea la matriz final, si el valor es -1 (valor original) copie el valor en la misma ubicación de la matriz inicial a final.
fuente
Aquí está mi solución. Como puede ver en el código, dada una matriz M * N, establece toda la fila en cero una vez que inspecciona un cero en esa fila. La complejidad temporal de mi solución es O (M * N). Estoy compartiendo toda la clase que tiene una matriz poblada estática para pruebas y un método de matriz de visualización para ver el resultado en la consola.
}
fuente