问题描述:

将n(n>1)个整数存放在一维数组R中,设计一个在时间和空间两方面都尽可能高效的算法。 将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据(x0,x1,x2,…x(n-1))变换为(xp,x(p+1),…,x(n-1),x0,x1,…,x(p-1))



示例:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

左移4位

[5, 6, 7, 8, 9, 10, 1, 2, 3, 4]



中间数组辅助法

解题思路:定义一个中间数组temp[ ] 来辅助 R[ ]数组 的元素进行移动。

  1. 看下面代码的reverse方法,共有3个for循环。这3个for循环,是该算法实现元素循环左移的核心代码.

假设数组R = [1,2,3,4,5,6,7,8,9,10] ,向左移动4位 (p = 4)

  1. 第一个for循环:将数组R中,前p个元素 暂存到 temp数组中。
  2. 第二个for循环:将数组R中,后n-p个元素整体左移p个位置。(其实左移用在这里不太恰当,应该说:将后n-p个元素的值 赋给 前n-p个元素)
  3. 第三个for循环:将第一个 for 循环中,暂存在 temp 数组中的元素,依序赋值给 R数组中的后p个元素
public class Solution_3 {

    public static void reverse(int[] R, int p) {
        //中间数组
        int[] temp = new int[R.length];

        //将R数组中,前p个元素 暂存到 temp数组中
        for (int i = 0; i < p; i++) {
            temp[i] = R[i];
        }

        //将R数组中,后n-p个元素整体左移p个位置
        for (int i = p; i < R.length; i++) {
            R[i-p] = R[i];
        }

        //将暂存在 temp 数组中的元素,依序赋值给 R数组中的后p个元素
        int start = 0;
        for (int i = R.length-p; i < R.length; i++) {
            R[i] = temp[start++];
        }

    }

    public static void main(String[] args) {
        int[] R = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int p = new Scanner(System.in).nextInt();
        reverse(R, p);
        //将数组以字符串格式打印输出
        System.out.println(Arrays.toString(R));
    }
}

时空复杂度:该算法只有单层循环,时间复杂度为O(n),因为外部内存中开了一个长度为n的中间数组,空间复杂度也为O(n)。



代码优化:前面reverse方法中,第一第二个代码我们可以进行合并。

解析:将元素暂存到temp数组 和 将R数组元素左移的步骤合并到一个for循环中。但需要注意的是,前面第一个for循环是直接将p个元素暂存到temp数组中。而合并后,是将n-p个元素暂存到temp数组中。因为R数组中有n-p个元素需要左移。

for (int i = 0; i < R.length-p; i++) { // T(n) = 3n = O(n)
    //将R数组中,前n-p个元素 暂存到 temp数组中
    temp[i] = R[i];
    //将R数组的后n-p个元素 赋值 给前面的n-p个元素
    R[i] = R[i + p];
}

时空复杂度:这一步并没有降低算法的时间复杂度,还是O(n)。仅仅只是代码量减少了


数组元素逆置法

解题思路:将R数组分割成a,b两个部分,然后分别将a,b两个部分的元素逆置,最后再将R数组整体逆置。所以需要三次调用元素逆置算法 。

java 位循环右移 数组循环左移java_数组

public class Solution_2 {

    private static void reverse(int[] R, int left, int right) {
        //数组元素互置算法(其实就是两个数的互换)
        for(int i = 0; i <= (right - left)/2; i++){
            int temp = R[left + i];
            R[left + i] = R[right - i];
            R[right - i] = temp;
        }
    }

    private static void move(int[] R, int n, int p) {
        //将数组中第一部分的元素逆置
        reverse(R,0,p - 1);

        //将数组中第二部分的元素逆置
        reverse(R, p,n - 1);

        //将整个数组的元素逆置
        reverse(R,0,n - 1);
    }

    public static void main(String[] args) {
        int[] R = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int p = new Scanner(System.in).nextInt();
        move(R, R.length, p);
        //以字符串格式,将数组打印输出
        System.out.println(Arrays.toString(R));
    }
}

时空复杂度:该算法中用的都是一重循环,时间复杂度为O(n),因为基本没有用到外部内存,空间复杂度为O(1)。