数组循环右移

描述:将一个长度为 n 的数组 A 的元素循环右移(ROR, Rotate Right)k 位,比如数组 1, 2, 3, 4, 5 循环右移 3 位之后就变成 3, 4, 5, 1, 2。
要求:只能用一个元素大小的附加存储,元素移动或交换次数为O(n)。

开始时自己想的算法就是最简单原始的一种:
每次将数组右移一位,循环k次:

void function(int *A,int n,int k){
    int tmp=A[n-1];
    for(int i=0;i<k;i++){
       for(int j=1;j<=n;j++){
         A[j]=A[j-1];
       }
       A[0]=tmp;
    }
}

但这个方法的时间复杂度是O(n*k),不符合题目要求,有没有更好的算法呢?

google了发现实现这个的是经典的“三步反转法”:
记 A 的前 n-k 位为 X,后 k 位为 Y,则 A=XY,将 A 循环右移 k 位后,应该得到YX。根据该算法,先将 A 整体倒置,得到 (XY )^T = Y^T • X^T,然后将前 k 位倒置,得到 Y • X^T,最后将后n-k 位倒置,得到 YX,正好是所求的结果。
这样我们可以将数组分为两段,先将它们全部倒置,再将前k位倒置,再将后n-k位倒置,即 1, 2, 3, 4, 5 变成 5, 4, 3, 2, 1,然后将前 k 位倒置,即 3, 4, 5, 2, 1,再将后n-k 位倒置,即 3, 4, 5, 1, 2,完成。

static void swap(int array[], int i, int j) {
    const int temp = array[i];
    array[i] = array[j];
    array[j] = temp;
}

static void reverse(int array[], int begin, int end) { 
    end--;
    while (begin < end)
        swap(array, begin++, end--);
}

void ror3(int *array, int n, int k) {
    k %= n;
    if (k == 0)
        return;

    reverse(array, 0, n);
    reverse(array, 0, k);
    reverse(array, k, n - k);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值