Java 减少以下代码的执行时间

Java 减少以下代码的执行时间,java,optimization,Java,Optimization,我正在解决一个问题。在17个测试用例中,有10个工作正常,并在不到1秒的时间内给出结果,但有7个用例需要2秒,超出了时间限制。下面是代码 import java.util.*; import java.io.*; class TestClass { static PrintWriter wr = new PrintWriter(System.out); public static void func1(int arr[], int n) { int

我正在解决一个问题。在17个测试用例中,有10个工作正常,并在不到1秒的时间内给出结果,但有7个用例需要2秒,超出了时间限制。下面是代码

import java.util.*;
import java.io.*;

class TestClass 
{
    static PrintWriter wr = new PrintWriter(System.out);

    public static void func1(int arr[], int n)
    {
        int temp = arr[0];
        for (int jj = 0; jj < n; jj++)
        {
            if (jj == (n - 1))
                arr[jj] = temp;
            else
                arr[jj] = arr[jj + 1];
        }
    }

    public static void func2(int arr[], int n, int rt) 
    {
        int count = 0;
        for (int a = 0; a < n; a++)
        {
            for (int b = a; b < n; b++)
            {
                if (arr[a] > arr[b])
                    count++;
            }
        }

        if (rt == (n - 1))
            wr.print(count);
        else
            wr.print(count + " ");
    }

    public static void main(String args[]) throws Exception 
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String str = br.readLine().trim();
        StringTokenizer st = new StringTokenizer(str);

        int t = Integer.parseInt(st.nextToken());

        for (int i = 0; i < t; i++)     //for test cases
        {
            str = br.readLine().trim();
            st = new StringTokenizer(str);
            int n = Integer.parseInt(st.nextToken());
            int arr[] = new int[n];
            str = br.readLine().trim();
            st = new StringTokenizer(str);

            for (int j = 0; j < n; j++)     //to take input of array for each test case
            {
                arr[j] = Integer.parseInt(st.nextToken());
            }

            for (int rt = 0; rt < n; rt++)    //for number of times circular shifting of array is done
            {
                func1(arr, n);    //circularly shifts the array by one position
                func2(arr, n, rt);  //prints the number of inversion counts
            }

            if (i != (t - 1))
                wr.println();
        }

        wr.close();
        br.close();
    }
}
import java.util.*;
导入java.io.*;
类TestClass
{
静态PrintWriter wr=新的PrintWriter(System.out);
公共静态无效函数1(int arr[],int n)
{
int temp=arr[0];
for(intjj=0;jjarr[b])
计数++;
}
}
如果(rt==(n-1))
wr.打印(计数);
其他的
wr.打印(计数+“”);
}
公共静态void main(字符串args[])引发异常
{
BufferedReader br=新的BufferedReader(新的InputStreamReader(System.in));
String str=br.readLine().trim();
StringTokenizer st=新的StringTokenizer(str);
int t=Integer.parseInt(st.nextToken());
for(inti=0;i
有人能建议如何优化代码,以减少执行时间吗。 我知道BufferReader和PrintWriter比Scanner和System.out.print花费的时间更少。我之前使用的是扫描仪和System.out.print,但后来为了节省时间对其进行了更改,但没有起到任何作用。我之前也没有使用func1和func2,只在main中执行了所有操作。两种情况下的时间保持不变。
我在所有情况下都会得到当前输出,因此代码是正确的,我只需要帮助优化它。

优化的第一条规则(已经决定这是必要的)是使用探查器。这会计算方法被调用的次数,测量每个方法内的累计时间,并向您提供一个报告

如果只运行几次,那么方法是否慢并不重要。如果你运行它数十万次,你需要让它更快,或者运行更少的次数

如果您使用的是主流IDE,那么您已经有了一个分析器。阅读它的文档并使用它


优化的另一个首要规则是,如果已经有关于您试图解决的问题的文献,请阅读。我们大多数人可能已经独立地发明了气泡排序。很少有人会想到快速排序,但这是一个更好的解决方案

看起来你好像在计算数组中的倒数。考虑到这种幼稚的方法,您的实现将尽可能地高效

for(int i=0; i< array.length; i++) {
   int n1 = array[i];
   for(int j=i+1; j< array.length; j++) {
       n2 = array[j];
       if(n1 > n2) {
           count++;
       }
   }
}
这是四个层次的循环。查看慢速测试的输入值,找出
n*n*n*t
是什么——这是一个指示它在内部块中执行工作的次数的指标

我们不知道你的算法应该实现什么。但是想想你是否在这些循环中做了两次同样的事情



看起来好像
func1()
应该旋转数组。查看
System.arrayCopy()
一次移动整个数组块。大多数CPU将在一次操作中完成此操作。

您使用的网站从过去的编程竞赛中获取问题。我认识到这是一个熟悉的问题

与大多数优化问题一样,首选步骤为:

  • 少做
  • 用更少的指令做同样的事情
  • 不要使用函数
  • 使用更快的指令
  • 在本例中,您有一个数组,希望将其旋转多次,然后从旋转的位置对其进行处理

    旋转阵列是一项极其昂贵的操作,因为通常需要将阵列中的每个元素复制到新位置。对您来说更糟糕的是,您使用的是最简单的方法,即每需要旋转一步,就旋转阵列一步

    因此,如果您有一个需要旋转45步的100元素数组,那么您将有(每个元素交换3个副本)100*45*3个副本来执行旋转

    在上面的示例中,更好的方法是找出一个例程,该例程一次旋转数组45个元素。有很多方法可以做到这一点。最简单的方法是将RAM需求翻一番,只需要两个阵列

    b[x]=a[(模(x+45),a.长度)]

    更快的“少做”方法是永远不要旋转数组,而是反向执行计算。这在概念上是旋转数组中所需索引与预旋转数组中实际索引的函数。这避免了所有的复制,索引号(由于在数学处理单元中被大量操作)将已经存储在CPU寄存器中,这是计算机拥有的最快的RAM

    请注意,一旦在原始数组中有了起始索引,就可以计算下一个索引
    for (int i = 0; i < t; i++) {
        // stuff removed
        for (int rt = 0; rt < n; rt++) {
            // snip
            func2(arr, n, rt);  //prints the number of inversion counts
        }
        // snip
    }
    
    public static void func2(int arr[], int n, int rt) {
        // snip
        for (int a = 0; a < n; a++) {
            for (int b = a; b < n; b++) {
                // stuff
            }
        }
        // snip
    }
    
    An example of a faster rotate that does less
        public static void func1(int arr[], int shift) {
            int offset = shift % arr.length;
    
            int [] rotated = new int[arr.length];
            // (arr.length - 1) is the last index, walk up till we need to copy from the head of arr
            for (int index = 0; index < (arr.length - 1) - offset; index++) {
                rotated[index] = arr[index+offset];
            }
            // copy the end of the array back into the beginning
            for ( int index = (arr.length - 1) - offset; index < arr.length; index++ ) {
                rotated[index] = (offset - ((arr.length - 1)  - index) - 1);
            }
    
            System.arraycopy(rotated, 0, arr, 0, arr.length);
        }