Java 如何在处理阵列时降低时间复杂度?在爪哇

Java 如何在处理阵列时降低时间复杂度?在爪哇,java,loops,optimization,time-complexity,Java,Loops,Optimization,Time Complexity,一个数组A包含n个元素,我们需要交换元素d多次。下面的代码适用于较小的n和d值,但当n和d值的顺序为10^5时。花费的时间是巨大的。如何优化代码 for(int i=0;i<d;i++){ int j=0; while((j<n-1)){ int temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; j++; }

一个数组A包含n个元素,我们需要交换元素d多次。下面的代码适用于较小的n和d值,但当n和d值的顺序为10^5时。花费的时间是巨大的。如何优化代码

for(int i=0;i<d;i++){
        int j=0;
        while((j<n-1)){
            int temp=a[j];
            a[j]=a[j+1];
            a[j+1]=temp;
            j++;
        }

    }
你能推荐一些好的资源来学习时间复杂度和代码优化吗

Integer[] temp = new Integer[d];

// store moved items in temp
for (int i = 0; i < d; i++) {
    temp[i] = a[i];
}

// replace once items in array
for (int j = 0; i < n - 1; i++) {
    a[j] = a[j+d];
}

// add on end the temp items
for (int i = 0; i < d; i++) {
    a[n + i] = temp[i];
}
这将通过d调用降低复杂性


这通过d次调用降低了复杂性

如果您仔细想想,您需要交换长度为n个元素的数组中所有元素的d次。这将生成一个在^2上的On*d,其中d=n。如果你真的需要交换每一个元素,在我看来没有任何改进

但是,如果您只想要结果,则此代码要好得多:

public static int[] change(int[] array, int d) {
    int[] tempArray = new int[array.length];
    for (int i = 0; i < array.length; ++i) {
        int place = Math.floorMod(i - d, array.length);       //calculating the new index for array[i]
        tempArray[place] = array[i];
    }
    return tempArray;
}

此代码具有打开状态。如果你知道模计算,你应该明白我在做什么

仔细想想,需要交换长度为n个元素的数组中所有元素的d倍。这将生成一个在^2上的On*d,其中d=n。如果你真的需要交换每一个元素,在我看来没有任何改进

但是,如果您只想要结果,则此代码要好得多:

public static int[] change(int[] array, int d) {
    int[] tempArray = new int[array.length];
    for (int i = 0; i < array.length; ++i) {
        int place = Math.floorMod(i - d, array.length);       //calculating the new index for array[i]
        tempArray[place] = array[i];
    }
    return tempArray;
}

此代码具有打开状态。如果你知道模计算,你应该明白我在做什么

如果算法的目的是将元素移位d次,那么实际上不需要两个循环:只需要一个循环

我用100000000大小的数组测试了您的,耗时5463秒

然而,我的解决方案耗时1702毫秒

交换实际上是不必要的。相反,使用插入排序技术更好

拟考虑的解决方案如下:

void rotate(int d) {
    for (int i = 0; i < d; i++) {
        rightShift();
    }
}

void rightShift() {
    int v = a[a.length - 1];
    for (int i = a.length - 2; i >= 0 ; i --) {
        a[i + 1] = a[i];
    }
    a[0] = v;
}
请注意,当d>=n时,不需要执行不必要的交换


要解决此问题,请使用d=d%n.

如果算法中的目的是将元素移位d次,那么实际上不需要两个循环:只需要一个循环

我用100000000大小的数组测试了您的,耗时5463秒

然而,我的解决方案耗时1702毫秒

交换实际上是不必要的。相反,使用插入排序技术更好

拟考虑的解决方案如下:

void rotate(int d) {
    for (int i = 0; i < d; i++) {
        rightShift();
    }
}

void rightShift() {
    int v = a[a.length - 1];
    for (int i = a.length - 2; i >= 0 ; i --) {
        a[i + 1] = a[i];
    }
    a[0] = v;
}
请注意,当d>=n时,不需要执行不必要的交换


要解决此问题,请使用d=d%n.

此处所做的是将阵列左移d位,而不使用分配额外存储

要按d位置左移,请执行以下操作:

反转整个阵列n/2交换 反转阵列n-d/2交换中的第一个n-d元素 反转阵列d/2交换中的最后d元素 它总共不交换n次,与d无关,因此其时间复杂度为On

您可以这样实现:

void reverse(int[] arr, int from, int to) {
  while (from+1 < to) {
    --to;
    int tmp = arr[from];
    arr[from] = arr[to];
    arr[to] = tmp;
    ++from;
  }
}

int n = arr.length;
reverse(arr, 0, n);
reverse(arr, 0, n-d);
reverse(arr, n-d, n);

这里要做的是将阵列左移d个位置,而不使用分配额外的存储

要按d位置左移,请执行以下操作:

反转整个阵列n/2交换 反转阵列n-d/2交换中的第一个n-d元素 反转阵列d/2交换中的最后d元素 它总共不交换n次,与d无关,因此其时间复杂度为On

您可以这样实现:

void reverse(int[] arr, int from, int to) {
  while (from+1 < to) {
    --to;
    int tmp = arr[from];
    arr[from] = arr[to];
    arr[to] = tmp;
    ++from;
  }
}

int n = arr.length;
reverse(arr, 0, n);
reverse(arr, 0, n-d);
reverse(arr, n-d, n);

你做同样的事情d次。删除外部循环将使其速度加快d倍。请使用列表而不是数组。使用列表,您可以删除一个位置上的对象,然后将其添加到other@AndyTurner我知道,如果没有for或while循环,我怎么做才是问题所在?@anatoli,但问题需要用数组来解决。不使用列表。一个绝对需要的优化是在循环外声明变量的j,temp,你做同样的事情d次。删除外部循环将使其速度加快d倍。请使用列表而不是数组。使用列表,您可以删除一个位置上的对象,然后将其添加到other@AndyTurner我知道,如果没有for或while循环,我怎么做才是问题所在?@anatoli,但问题需要用数组来解决。不使用列表。一个绝对需要的优化是在循环外声明变量的j,temp。值得指出的是,用两个对System.arraycopy的调用来替换循环会更简单,尽管更不透明:System.arraycopyarray,d,tempArray,0,n-d;System.arraycopyarray,n-d,tempArray,n-d,d;,谢谢@AndyTurner我不知道这一点,因为我刚刚开始学习Java。但它非常具有中断性。@AndyTurner,但第二次调用不需要是System.arraycopyarray,0,tempArray,n-d,d;?首先,复制从d开始到原始数组末尾的所有元素。现在我们需要将数组从索引0复制到索引d,否则我错了吗?你很可能是对的。我说了一些类似的话;值得指出的是,将循环替换为对System.arraycopy的两个调用会更简单,尽管更不透明:System.arraycopyarray,d,tempArray,0,n-d;System.arraycopyarray,n-d,tempArray,n-d,d;,或
类似的东西。谢谢@AndyTurner我不知道这一点,因为我刚刚开始学习Java。但它非常具有中断性。@AndyTurner,但第二次调用不需要是System.arraycopyarray,0,tempArray,n-d,d;?首先,复制从d开始到原始数组末尾的所有元素。现在我们需要将数组从索引0复制到索引d,否则我错了吗?你很可能是对的。我说了一些类似的话;如果你仔细想想,你仍然在使用两个循环。在rotate中,是一个for循环,在该循环中,您使用另一个for循环调用rightShift。因此,时间复杂度仍然是*d。如果你仔细想想,你仍然在使用两个循环。在rotate中,是一个for循环,在该循环中,您使用另一个for循环调用rightShift。因此,时间复杂度仍然是*d。