在线性时间内旋转数组的算法

时间:2010-12-16 03:52:34

标签: arrays algorithm

如何仅在线性时间内使用i函数将整数数组旋转swap次。

22 个答案:

答案 0 :(得分:46)

您可以使用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)
{
   ...
}

使用交换实现reverse(int array[], int pos_from, int pos_to)留给读者练习。提示:这可以在线性时间内完成。

答案 1 :(得分:18)

我们假设有一个名为arr_reverse(arr,i,j)的函数,它使用arr函数在索引ij之间反转数组swap的元素。

示例:

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

然后该函数将返回:

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

实现此功能是直截了当的,O(N)

现在让我们在旋转数组时使用此功能。

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} 
        ^^^^^^^^^

整个过程使用arr_reverse 3次,使其成为O(N)

答案 2 :(得分:4)

这是一个更好的解决方案,与其他解决方案不同。它涉及的阵列交换少于其他阵列交换。的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

答案 3 :(得分:2)

使用线性时间O(2N + m)和恒定空间O(4)。 m = GCD(n,p)

它比交换方法快50%,因为交换需要将O(N)次写入临时。

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

答案 4 :(得分:1)

天真的伪代码实现:

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

反复将最后一个元素移动到前面,在移动之前移动到前面的任何内容之前停止

答案 5 :(得分:1)

更好地使用直接简单的功能,复杂性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
}

答案 6 :(得分:1)

简短答案(Python代码)

def reverse(arr, i, j):
    for idx in xrange((j - i + 1) / 2):
        arr[i+idx], arr[j-idx] = arr[j-idx], arr[i+idx]

def solution(A, K):
    l = len(A)
    if l == 0:
        return []
    K = K%l
    reverse(A, l - K, l -1)
    reverse(A, 0, l - K -1)
    reverse(A, 0, l - 1)
    return A

详细答案(代码说明)

首先让我谈谈K < N的基本情况,这种情况下的想法是将数组分为两部分ABA是第一个N-K个元素数组和B个最后的K个元素。该算法分别反转AB,最后反转整个数组(两部分分别反转)。要使用K > N处理情况,请考虑每次将数组N反转一次,然后再次获得原始数组,因此我们可以使用模块运算符查找拆分数组的位置(仅反转真正有用的时刻,避免无用的转移。

一个图形化的分步示例可以帮助您更好地理解该概念。请注意

  • 粗线表示数组的分割点(在此示例中,K = 3);
  • 两个红色数组分别表示输入和预期输出。

开始于:

first array

看起来,我们想要在最终输出前面的是倒数的最后3个字母,现在让我们将其倒置到位(算法的第一个倒数):

second array

现在反转前N-K个元素(算法的第二个反转):

third array

我们已经有了解决方案,但是在相反的方向上,我们可以通过反转整个数组来解决它(算法的倒数第三次):

final array

这是最终输出,原始数组以K = 3循环旋转。

让我们从pythonp开始,再给出一个逐步的示例,

A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
K = 22
N = len(A)

我们找到分裂指数:

K = K%N
#2

因为在这种情况下,前20个移位将无用,所以现在我们反转原始数组的最后K(2)个元素:

reverse(A, N-K, N-1)
# [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]

如您所见9和10发生了移位,现在我们反转前N-K个元素:

reverse(A, 0, N-K-1)
# [8, 7, 6, 5, 4, 3, 2, 1, 10, 9]

最后,我们反转整个数组:

reverse(A, 0, N-1)
# [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]

请注意,反转数组的时间复杂度为O(N)。

答案 7 :(得分:1)

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

答案 8 :(得分:0)

为什么只交换功能?

O(n)在时间和空间上:

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

答案 9 :(得分:0)

此算法最多可进行len(array)-1交换,并且适用于正(右)和负(左)旋转量。数组被就地修改。
与其他类似方法不同,它不需要计算GCD。

(Python 3)

def rotate(array,amount):
    if amount<0:
        amount+=len(array)
    a=0
    b=0
    for _ in range(len(array)-1):
        b=(b+amount) % len(array)
        if b==a:
            a+=1
            b=a
        if b!=a:
            array[a],array[b] = array[b],array[a] #swap array[a],array[b]
    return array

A diagram drawn in MS Paint
当一个周期不够用时(如果在到达每个索引之前返回到开始),请从下一个索引开始一个新的周期。

注意:旋转项目a,b,c,d,...可以使用
完成 swap a,b swap a,c swap a,d ...

答案 10 :(得分:0)

我的Java解决方案

3.3.2

答案 11 :(得分:0)

  

用于圆形右旋。

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

答案 12 :(得分:0)

这是我的回答使用js希望这有帮助 其中k是您要预先形成的旋转数

 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;

答案 13 :(得分:0)

在{python:

中实现此目的的O(1)方法
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

这基于this answer about using a 1-based list in python

如果你试图将一个项目从列表的末尾开始索引,它会产生轻微的故障,它将从(新)开始返回项目,而小于大小减去偏移量的负数指标将不起作用。

答案 14 :(得分:0)

这是一个可在O(n)中运行的小片段,用JavaScript编写。 关键概念是,您始终必须使用替换项目。

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

答案 15 :(得分: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);

}

答案 16 :(得分:0)

仅使用swap,以下是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));
    }
  }
}

您可以在http://pointer-overloading.blogspot.in/2013/09/algorithms-rotating-one-dimensional.html

了解更多相关信息

答案 17 :(得分: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
 */

答案 18 :(得分: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]);
        }
    }
}

答案 19 :(得分:-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);
}

答案 20 :(得分:-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;
}

答案 21 :(得分:-1)

<div class="box">
  <div class="content">
    
  </div>
</div>