数组k平移三种方法(java)

上代码,本文用了三种方法实现,时间复杂度不一样,空间复杂度都是o(1):

public class ArrayKMove {

    /**
     * 问题:数组的向左k平移,k小于数组长度
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        ArrayKMove kmove = new ArrayKMove();
        kmove.methodOne();
        kmove.methodTwo();
        kmove.methodThree();
    }

    private static final int i = 10000;
    private static final int testNum = 1000;
    private int a[];
    private long startTime = 0, timeSpan = 0;

    public ArrayKMove() {
        a = new int[i];
        for (int j = 0; j < i; j++) {
            a[j] = j;
        }
    }

    public void printArray() {
        for (int j = 0; j < i; j++) {
            System.out.println(a[j]);
        }
    }

    public void methodOne() {
        this.startTime = System.currentTimeMillis();
        for (int k = 1; k <= testNum; k++) {
            for (int j = 0; j < k; j++) {
                this.moveArrayFirstToLast();
            }
        }
        this.timeSpan = System.currentTimeMillis() - this.startTime;
        System.out.println("第一种方法消耗时间:" + timeSpan + "毫秒");
    }

    public void moveArrayFirstToLast() {
        int m = a[0];
        for (int j = 1; j < i; j++) {
            a[j - 1] = a[j];
        }
        a[i - 1] = m;
    }

    public void methodTwo() {
        this.startTime = System.currentTimeMillis();
        for (int j = 1; j <= testNum; j++) {
            this.swapArray(1, j);
            this.swapArray(j + 1, i);
            this.swapArray(1, i);
        }
        this.timeSpan = System.currentTimeMillis() - this.startTime;
        System.out.println("第二种方法消耗时间:" + timeSpan + "毫秒");
    }

    public void swapArray(int start, int end) {
        for (int s = start - 1, e = end - 1; s < e; s++, e--) {
            int temp = a[s];
            a[s] = a[e];
            a[e] = temp;
        }
    }

    public int gcdTwoInt(int m, int n) {
        if (m <= 0 && n <= 0)
            return 0;
        if (m <= 0 || n <= 0)
            return m <= 0 ? n : m;
        int g;
        while (n > 0) {
            g = m % n;
            m = n;
            n = g;
        }
        return m;
    }

    public void moveByGCD(int k) {
        if (k <= 0)
            return;
        int m = this.gcdTwoInt(k, i);
        for (int j = 0; j < m; j++) {
            int c = a[j];
            int p;
            for (p = (j + k) % i; p != j; p = (p + k) % i) {
                a[(p - k + i) % i] = a[p];
            }
            a[(p - k + i) % i] = c;
        }
    }

    public void methodThree() {
        this.startTime = System.currentTimeMillis();
        for (int j = 1; j <= testNum; j++) {
            this.moveByGCD(j);
        }
        this.timeSpan = System.currentTimeMillis() - this.startTime;
        System.out.println("第三种方法消耗时间:" + this.timeSpan + "毫秒");
    }
}

方法一:基本方法,每次左移一位,移动k次即可,但是时间复杂度是o(kn),这个方法可以用牺牲空间复杂度来提升时间效率,即用一个数组保存要平移的k个数据,把原数组直接平移k位后,再把k位数据直接插在后面k个位置即可,时间复杂度o(n)

方法二:先把前k位翻转,再把后面的n-k位翻转,然后整体翻转,这个画图可以证明。

方法三:不是很好理解,基本思路就是,循环替换,用i+k的值替换i处的值,但是是循环,也就是不能数组越界,还有就是要分m条路线,m是n和k的最大公约数。

测试规模:

数组大小10000

测试次数1000

每次平移的位数依次为1-1000次;

 

测试结果:

第一种方法消耗时间:5364毫秒

第二种方法消耗时间:21毫秒

第三种方法消耗时间:129毫秒

 

结果分析:

三种方法空间复杂度都是o(1)

时间复杂度依次为o(kn)o(3n)o(n)

但是测试时间第三种方法消耗的时间却比第二种大,原因是第三种方法中有求解两个最大公约数的操作,而且有运算较为复杂的求余运算,所以消耗时间增加,方法二中只有交换赋值的操作,比较简单。

原文地址:https://www.cnblogs.com/nannanITeye/p/3378750.html