2010-12-16 16 views
23

Cómo rotar una matriz de enteros por i veces usando la función swap solo en tiempo lineal.Algoritmo para girar una matriz en tiempo lineal

+5

Por favor, elabore su pregunta un poco. ¿Qué dimensión tiene la matriz? ¿Qué quiere decir con "girar una matriz"? Da un ejemplo de entrada y salida. Considere usar signos de puntuación y letras mayúsculas cuando corresponda. –

+0

¿Qué has probado? ¿Cómo no funciona? IOW, primero debe intentarlo antes de que lo ayudemos (no vamos a escribirlo) – KevinDTimm

+0

@sven supongamos que la matriz de entrada es {1,2,3,4,5} matriz de salida después de que una rotación a la derecha es {5, 1,2,3,4}. –

Respuesta

43

Usted puede hacer esto en un tiempo lineal mediante el uso de un() ayudante inversa.

// 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 reverse(int array[], int pos_from, int pos_to) utilizando permutas se deja como ejercicio para el lector. Sugerencia: esto se puede hacer en tiempo lineal.

+1

Solo tengo curiosidad por qué funciona todo el tiempo – daydreamer

+2

@daydreamer Puede consultar este documento: http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf Si cambia el segundo y el tercer reverso en el código de Sanjit, es más fácil de entender. –

+3

El enlace no funciona. ¿Puedes proporcionar un enlace con una prueba para este método? – Daggerhunt

1

una ingenua aplicación pseudocódigo:

for (n = 0; n < i; n++) { 
    for (j = array.length-1; j > n; j--) 
     swap(j, j-1) 
} 

repetidamente mueve el último elemento en la parte delantera, deteniéndose antes de que se mueve nada se movió con anterioridad a la parte delantera

+1

probé la misma solución, pero la quiero en o (n) –

+10

@prp - Podría haber mencionado eso en la pregunta, ¿eh? –

0

por qué sólo la función de intercambio?

O (n) en el tiempo y en 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); 
+0

¿por qué votar abajo? Este código funciona! – Stuck

+0

Este código no funciona. Pruebe rotarCount = 8, produce: 9,10,2,3,4,5,6,7,8,1. – Nixuz

+0

@Nixuz: corrigió ese error – Stuck

18

Digamos que tenemos una función llamada arr_reverse(arr,i,j) que invierte los elementos de la matriz arr entre el índice y ij usando la función swap.

Ejemplo:

arr = {1,2,3,4,5} 
i = 0 
j = 2 

entonces la función devolverá:

{3,2,1,4,5} 
^^^^^ 

La implementación de esta función es sencillo y es O(N).

Ahora usemos esta función para hacer girar 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, por lo que es O(N)

+0

Creo que cometió un error tipográfico en los pasos 2 y 3 de su ejemplo, donde muestra el resultado. Tienes los 4 y 5 volteados de lo que deberían ser. – Nixuz

+0

@Nixuz: gracias por notarlo. – codaddict

1

mejor uso una función directa y simple, la 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 
} 
4

Aquí es una solución mejor, de una naturaleza diferente a los demás. Implica menos cambios de matriz que los demás.Python:

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 
0
/* 
* 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]); 
     } 
    } 
} 
0
/* 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 
*/ 
0

utilizando únicamente de intercambio, que sigue es una implementación en 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)); 
    } 
    } 
} 

Usted puede leer más sobre él en http://pointer-overloading.blogspot.in/2013/09/algorithms-rotating-one-dimensional.html

0
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); 

}

+0

Esto es idéntico a la respuesta aceptada, que también vino 3 años antes. ;) –

0

Aquí hay un pequeño fragmento eso es obras en O (n), escrito en JavaScript. El concepto clave es que siempre debe 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)) 
0

Un O(1) método de 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 this answer about using a 1-based list in python.

Esto tiene la falla leve que si intenta indexar un elemento del final de la lista, devolverá elementos del (nuevo) principio, y los índices negativos menores que el tamaño menos el desplazamiento no funcionarán .

-1
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); 
} 
+3

pidió una matriz de enteros para invertir. not 'string' – Riad

0

aquí es mi respuesta usando js espero que esta ayuda donde k es el número de las rotaciones que desea preformas

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; 
0
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++; 
    } 

} 

Doug McIlroy’s Handwaving Description

-1
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; 
} 
0

Para rotación circular a la derecha.

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()]); 
    } 
} 
+0

Aquí tomamos las entradas en un orden tal que la entrada se ve como si se tomara de la manera girada a la derecha. –

Cuestiones relacionadas