arrays - sistemas - Algoritmo para rotar una matriz en tiempo lineal.
rotacion de vectores (18)
Cómo rotar una matriz de enteros i
veces utilizando la función de swap
solo en tiempo lineal.
Para rotación a la derecha circular.
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int k = scan.nextInt() % n;
int q = scan.nextInt();
int arr[] = new int[n];
for (int i = 0; i < n; i++)
{
int a = i + k;
int pos = (a < n) ? a : a - n;
arr[pos] = scan.nextInt();
}
for (int j = 0; j < q; j++)
{
System.out.println(arr[scan.nextInt()]);
}
}
¿Por qué solo cambiar la función?
O (n) en el tiempo y el espacio:
var rotateCount = 1;
var arr = new Array(1,2,3,4,5,6,7,8,9,10);
tmp = new Array(arr.length);
for (var i = 0; i<arr.length; i++)
tmp[(i+rotateCount)%arr.length]=arr[i];
arr = tmp;
alert(arr);
Aquí está mi respuesta usando js Espero que esto ayude donde k es el número de rotaciones que desea realizar.
var arrayRoatate=function(array,k){
for(;k>0;k--) {
var nextElementValue=undefined;
for (var i = 0; i < array.length; i=i+2) {
var nextElement = i + 1;
if (nextElement >= array.length)
nextElement = nextElement - array.length;
var tmp=array[i];
if(nextElementValue!==undefined)
array[i]=nextElementValue
nextElementValue=array[nextElement];
array[nextElement]=tmp;
}
}
return array;
Aquí hay un pequeño fragmento que funciona en O (n), escrito en JavaScript. El concepto clave es que siempre tiene que trabajar con el elemento reemplazado.
function swap(arr, a, v) {
var old = arr[a];
arr[a] = v;
return old;
}
function rotate(arr, n) {
var length = arr.length;
n = n % length;
if(!n) return arr;
for(var cnt = 0,
index = 0,
value = arr[index],
startIndex = index;
cnt < length;
cnt++) {
// Calc next index
var nextIndex = mapIndex(index, n, length);
// Swap value with next
value = swap(arr, nextIndex, value)
if(nextIndex == startIndex) {
startIndex = index = mapIndex(index, 1, length);
value = arr[index];
} else {
index = nextIndex;
}
}
return arr;
}
function mapIndex(index, n, length) {
return (index - n + length) % length;
}
console.log(rotate([1,2,3,4,5,6,7,8,9], 5))
console.log(rotate([1,2,3,4,5,6], 2))
Aquí hay una mejor solución, de una naturaleza diferente a las otras. Implica menos cambios de matriz que los otros. Pitón:
import fractions
# rotates an array in-place i positions to the left, in linear time
def rotate(arr,i):
n = len(arr)
reps = fractions.gcd(n,i)
swaps = n / reps
for start in xrange(reps):
ix = start
tmp = arr[ix]
for s in xrange(swaps-1):
previx = ix
ix = (ix + i) % n
arr[previx] = arr[ix]
arr[ix] = tmp
return arr
Digamos que tenemos una función llamada arr_reverse(arr,i,j)
que invierte los elementos de la matriz arr
entre el índice i
y j
usando la función de swap
.
Ejemplo:
arr = {1,2,3,4,5}
i = 0
j = 2
entonces la función volverá:
{3,2,1,4,5}
^^^^^
Implementar esta función es sencillo y es O(N)
.
Ahora vamos a usar esta función para rotar la matriz.
arr = {1,2,3,4,5} // input array
k = 2 // amount of right rotation
result = {4,5,1,2,3} // expected result
l = 5 // length of array.
Step 1: Call arr_reverse(arr,l-k,l-1) which is arr_reverse(arr,3,4)
we get {1,2,3,5,4}
^^^
Step 2: Call arr_reverse(arr,0,l-k-1) which is arr_reverse(arr,0,2)
we get {3,2,1,5,4}
^^^^^
Step 3: Call arr_reverse(arr,0,l-1) which is arr_reverse(arr,0,4)
we get {4,5,1,2,3}
^^^^^^^^^
Todo el proceso hace uso de arr_reverse
3 veces, haciéndolo O(N)
Mejor uso de una función directa y simple, complejidad N:
int rotate(int* a,int DIM,int rn,int* b) {
int i; //counter
for(i=0;i<DIM;i++){ // looping through the array
b[(i+rn)%len]=a[i]; // copying the values in the b array=a shifted with rn(+ for right or - for left shifting
}
Puedes hacer esto en tiempo lineal usando un ayudante reverse ().
// rotate array of size=size, by n positions
void rotate(int array[], int size, int n)
{
// reverse array[0...size-1]
reverse(array, 0, size-1);
// reverse A[0...n-1]
reverse(array, 0, n-1);
// reverse A[n...size-1]
reverse(array, n, size-1);
}
// reverse elements in the array[pos_from ... pos_to]
void reverse(int array[], int pos_from, int pos_to)
{
...
}
La implementación de reverse(int array[], int pos_from, int pos_to)
usando swaps se deja como un ejercicio para el lector. Sugerencia: Esto se puede hacer en tiempo lineal.
Un método O(1)
para lograr esto, en python:
class OffsetList(list):
__slots__ = ''offset''
def __init__(self, init=[], offset=-1):
super(OffsetList, self).__init__(init)
self.offset = offset
def __getitem__(self, key):
return super(OffsetList, self).__getitem__(key + self.offset)
def __setitem__(self, key, value):
return super(OffsetList, self).__setitem__(key + self.offset, value)
def __delitem__(self, key):
return super(OffsetList, self).__delitem__(key + self.offset)
def index(self, *args):
return super(OffsetList, self).index(*args) - self.offset
Esto se basa en esta respuesta sobre el uso de una lista basada en 1 en python .
Esto tiene el ligero problema de que si intenta indexar un elemento fuera del final de la lista, devolverá los elementos desde el comienzo (nuevo), y los indicadores negativos menores que el tamaño menos el desplazamiento no funcionarán.
Una implementación de pseudocódigo ingenua:
for (n = 0; n < i; n++) {
for (j = array.length-1; j > n; j--)
swap(j, j-1)
}
Mueve repetidamente el último elemento al frente, deteniéndose antes de que mueva cualquier cosa que se haya movido previamente al frente
Usando el tiempo lineal O (2N + m) y el espacio constante O (4). m = GCD (n, p)
Es hasta un 50% más rápido que el enfoque de intercambio, ya que el intercambio requiere escribir O (N) veces en forma temporal.
http://www.eis.mdx.ac.uk/staffpages/r_bornat/oldteaching/I2A/slides%209%20circshift.pdf
for (m=0, count=0; count!=n; m++) {
type t=A[m];
for (i=m, j=m+p; j!=m; i=j, j = j+p<n ? j+p : j+p-n, count++)
A[i]=A[j];
A[i]=t; count++;
}
usando solo swap, a continuación se muestra una implementación de C ++
template<class T>
void rotate_array(std::vector<T> *array, int i) {
int n = array->size();
i = i % n;
int gcd_n_i = gcd(i, n);
for (int j = 0; j < gcd_n_i; j++) {
T first_element = array->at(j);
for (int k = j; (k + i) % n != j; k = (k + i) % n) {
std::swap(array->at(k), array->at((k + i) % n));
}
}
}
Puede leer más sobre esto en http://pointer-overloading.blogspot.in/2013/09/algorithms-rotating-one-dimensional.html
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package rotateinlineartime;
/**
*
* @author Sunshine
*/
public class Rotator {
void reverse(int a[], int n) {
for (int i = 0; i <= n - 1; i++) {
int temp;
temp = a[i];
a[i] = a[n - 1];
a[n - 1] = temp;
n--;
}
printArray(a);
}
void printArray(int a[]) {
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
}
/* Q: How can we shift/rotate an array in place?
A: "in place" means O(1) space complexity, so we need to do some trick
*/
#include <iostream>
#include <algorithm>
using namespace std;
void ArrayRotate(int a[], int n, int k)
{
if (n < 1 || k % n == 0 ) return;
k %= n;
if (k < 0) k += n;
reverse(a, a+k);
reverse(a+k, a+n);
reverse(a, a+n);
}
void PrintArray(int a[], int n)
{
for ( int i = 0 ; i < n; ++i)
cout << a[i] << " ";
cout << endl;
}
int main()
{
int a[] = { 1, 2 , 3, 4, 5 };
int n = sizeof(a)/sizeof (a[0]);
PrintArray(a, n);
ArrayRotate(a, n, 2);
PrintArray(a, n);
return 0;
}
/* Output:
1 2 3 4 5
3 4 5 1 2
*/
Simple Solution in O(n) time and using O(1) space:
for e.g 1,2,3,4,5,6,7
rotating 2 times
start with index 2, store a[0] as last
Iteration 1: 1,2,1,4,3,6,5 (1-->3-->5-->7)
Iteration 2: 1,7,1,2,3,4,5 (2-->4-->6)
replace 1 with 6 (last value).
public int[] roatateArray(int[] a,int k)
{
int last = a[0];
int start = k;
for(int j=0;j<k;j++) {
for(int i=start;i<a.length;i+=k)
{
int tmp=a[i];
a[i]=last;
last=tmp;
}
start--;
if (start<=0) break;
}
a[0]=last;
return a;
}
public int[] shift(int[] A, int K) {
int N = A.length;
if (N == 0)
return A;
int mid = -K % N;
if (mid < 0)
mid += N;
if (mid == 0)
return A;
reverseSubArray(A, 0 , mid - 1);
reverseSubArray(A, mid , N - 1);
reverseSubArray(A, 0 , N - 1);
return A;
}
private void reverseSubArray(int[] A, int start , int end){
int i = 0;
int tmp;
while (i < (end - start + 1) / 2) {
tmp = A[i + start];
A[i + start] = A[end - i];
A[end - i] = tmp;
i++;
}
}
public static String rotateKTimes(String str,int k){
int n = str.length();
//java substring has O(n) complexity
return str.substring(n-k) + str.substring(0,n-k);
}
void reverse_array(int a[], int start, int end){
while(start < end){
int temp = a[start];
a[start] = a[end];
a[end] = temp;
start++;
end--;
}
}
void rotate_array(int a[], int pivot, int len){
int i;
/*Reverse the whole array */
reverse_array(a, 0, len);
/* Reverse from 0 to pivot and pivot to end */
reverse_array(a,0, pivot);
reverse_array(a,pivot+1,len);
}