编程之美---数组循环移位

设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为 O(N), 且只允许使用两个附加变量。

解法一:

简单的办法是,每次将数组中的元素右移一位,循环K次。abcd1234 -> 4abcd123 -> 34abcd12。

代码如下:

public static void rightShift(int[] array, int len, int k){
        while(k > 0){
            int temp = array[len-1];
            for(int i = len-1; i > 0; i--){
                array[i] = array[i-1];
            }
            array[0] = temp;
            k--;
        }
    }

算法的时间复杂度为 O(K*N)。
当K是一个远大于N的数时,上面的解法就需要改进了。当 k=50000000时,移位所需要的时间如下:
《编程之美---数组循环移位》

解法二:

观察循环右移的特点后,发现每个元素右移N位后,都会回到原来的位置,因此右移 K 位跟右移 k%N 位的结果是一样的,算法改进如下:

public static void rightShift(int[] array, int len, int k){
        k %= len;
        while(k > 0){
            int temp = array[len-1];
            for(int i = len-1; i > 0; i--){
                array[i] = array[i-1];
            }
            array[0] = temp;
            k--;
        }
    }

解法三:

假设原数组为12345678,循环右移4位后变为56781234。其中 5678 和 1234的顺序是不变的,可以将这两段当做整体,右移K位就是将这两段的顺序交换。

  1. 逆序排列 1234: 12345678 -> 43215678
  2. 逆序排列 5678: 43215678 -> 43218765;
  3. 整体逆序: 43218765 -> 56781234。

代码如下:

public static void reverse(int[] array, int start, int end){
        for(; start < end; start++, end--){
            int temp = array[end];
            array[end] = array[start];
            array[start] = temp;
        }
    }

    public static void rightShift(int[] array, int len, int k){
        k %= len;
        reverse(array, 0, len-k-1);
        reverse(array, len-k, len-1);
        reverse(array, 0, len-1);
    }

当k=50000000时,所花时间如下:
《编程之美---数组循环移位》

可以看到效率有了明显提升。

    原文作者:dzq_feixiang
    原文地址: https://blog.csdn.net/dzq_feixiang/article/details/51734364
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞