¿Hay alguna manera de girar a la izquierda / derecha una matriz binaria en menos de O (n) tiempo?

Depende de lo que desee hacer con él y de si está dispuesto a tratar la matriz como un tipo de datos abstractos, en lugar de un tipo nativo “directo”. Podemos definir una estructura de datos que conserve el acceso aleatorio en tiempo constante y la adición y eliminación amortizadas en tiempo constante tanto a “frente” como a “atrás”: la cola de doble extremo, implementada como una matriz dinámica. Consulte Cola doble: Wikipedia (aunque ese artículo gasta demasiado tiempo en la implementación puramente funcional a expensas de la implementación basada en matriz).

Aquí está la idea básica: en lugar de tratar una secuencia de bytes como una matriz lineal, trátela como un búfer circular. Esto significa que necesita punteros al inicio y al final de los valores almacenados reales. Para insertar al final, aumente el puntero final en uno (ajustando si es necesario). Para insertar al principio, disminuya el puntero inicial en uno (nuevamente, ajustando). La eliminación desde el principio y el final son lo opuesto.

0010101xxxxxxxxxxxxxxxxxxxx10101111111
^ fin ^ comienzo

// Insertar “1” en los resultados finales en:
00101011xxxxxxxxxxxxxxxxxxx10101111111
^ fin ^ comienzo

// Eliminar de los resultados iniciales en:
00101011xxxxxxxxxxxxxxxxxxxx0101111111
^ fin ^ comienzo

Cuando begin = end, la cola está llena y necesitamos asignar un búfer circular más grande. Si duplicamos el tamaño cada vez que produce tiempo constante amortizado para inserciones (al igual que append-at-end en una implementación de matriz lineal como std :: vector)

Con esta estructura de datos, podemos realizar una rotación de un solo bit mediante la combinación de una eliminación de un extremo y una inserción en el otro. También podemos atravesar el búfer circular para copiar todos los datos en tiempo O (n), lo mismo que una matriz lineal, o especializar la implementación para realizar operaciones bit a bit con otra deque en tiempo O (n) también.

std :: deque es parte del estándar C ++ pero puede implementarse de una manera algo diferente donde el búfer se divide en trozos de tamaño fijo, para evitar la copia.

Si solo tiene una matriz, debe mover cada elemento. Pero con una matriz circular, puede hacer rotaciones en el tiempo O (1).

Imagine que sus datos se almacenan en un círculo, con un puntero al punto de partida. Para hacer una rotación, en lugar de mover cada elemento, simplemente podemos aumentar o disminuir el índice inicial.

Ahora tiene que descubrir cómo calcular en qué índice buscar un elemento, dado su índice inicial y el índice de nuestro punto de partida. Debes tratar de descubrir la fórmula por ti mismo, pero si te atascas, puedes preguntar en los comentarios.