如何在没有额外堆内存的情况下循环移位阵列?

时间:2012-12-06 03:54:01

标签: algorithm

如何编写函数shift(int* arr, int k)将数组循环移位一个整数k?我不能从堆中说出“malloc”内存。

例如,使用伪代码,shift([1, 2, 3, 4], 2)返回[3, 4, 1, 2]shift([3, 1, 5, 5], 103)返回[1, 5, 5, 3]。我已经尝试使用模数来实现这种效果,如这个Java程序所示,其中我基本上迭代了一半的数组和交换值。

public static int* shift(int* arr, int k) {
  int half_array_len = arr.length / 2;
  for (int i = 0; i < half_array_len; ++i) {
    // Swap!
    int newIndex = (i + k) % arr.length;
    int temp = arr[i];
    arr[i] = arr[newIndex];
    arr[newIndex] = arr[i];
  }
  return arr;
}

但是,我相信这个功能仅适用于偶数长的数组。

如何为任何长度的数组实现shift?答案可以使用您想要的任何语言(Java,C ++,Ook Ook!等)。

2 个答案:

答案 0 :(得分:8)

(之前已被问过几次。)基本上,在Bentley的“编程珍珠”(Juggling,Reversal和Block Swap算法)中描述和分析了三个专门用于解决这个问题的经典就地算法。这些幻灯片详细描述了它们

http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf

最简单的算法是反转算法。只需反转整个阵列,然后单独反转每个[n - k]和[k]块。完成。 (从哪一端计算[k]块取决于移位的方向。)

当然,首先对k进行规范化是有意义的,即k = k % n以确保k小于n

P.S。在C ++中,答案是使用std::rotate,它完全符合您的要求。但我怀疑这是你寻求的答案。虽然你可能想看看std::rotate的一些实现(如果只发现它们通常使用Reversal算法:)

答案 1 :(得分:1)

我假设您的意思是您只能使用恒定数量的额外空间来执行此功能。可以使用以下算法(Python)在O(n*(k mod n))时间内使用一个临时值完成:

def shift_one(array):
    temp = array[-1] #put last element of array in a temp
    for i in range(len(array)-1)[::-1]:
        array[i+1] = array[i] #put each element in the next slot
    array[0] = temp #then put the temp at the beginning
    return array

def shift(array, k):
    for i in range(k%len(array)):
        array = shift_one(array)
    return array

如果你实际上并不局限于恒定的额外空间,你可以使用以下算法在k时间O(n)额外的空间(几乎相同的事情):{/ p>

def shift(array, k):
    k = k % len(array) #shifting by len(array) does nothing
    temp = array[-k:] #copy out the last k elements
    for i in range(len(array)-k)[::-1]:
        array[i+k] = array[i]
    array[:k] = temp
    return array

另外,如果你有像Python这样的列表可以比数组更多,那么有一个非常简单的解决方案:

def shift(array, k):
    #take the last k elements and put them at the front
     return array[-k:]+array[:-k]