【问题标题】:Why am I getting Time Limit Exceeded (TLE) error when using ArrayList<String[]> instead of int[][]?为什么在使用 ArrayList<String[]> 而不是 int[][] 时出现 Time Limit Exceeded (TLE) 错误?
【发布时间】:2020-06-26 20:28:30
【问题描述】:

所以我试图实现最短距离对的 Floyd-Warshal 算法。我的算法的第一个实现导致超出时间限制,而使用 2d 数组的第二个版本成功。谁能指出为什么 TLE 在第一个实现中出现?
注意:1000000 = 无穷大

输入: 输入的第一行包含一个整数 T,表示测试用例的数量。然后是 T 测试用例。每个测试用例的第一行包含一个整数 V,表示邻接矩阵的大小。接下来的 V 行包含矩阵(图形)的 V 空间分隔值。所有输入都是整数类型。

输出: 对于每个测试用例,输出将是 V*V 空间分隔的整数,其中第 i-j 个整数表示第 i 个顶点到第 j 个顶点的最短距离。对于 INT_MAX 整数输出 INF。

示例输入:

2
2
0 25
10000000 0
3
0 1 43
1 0 6
10000000 10000000 0

样本输出:

0 25 
INF 0 
0 1 7 
1 0 6 
INF INF 0 

代码方法1(给出TLE):

/*package whatever //do not write package name here */

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

class GFG {
    public static int parseInt(String no){
        if(no.equals("10000000") || no.equals("INF")){
            return Integer.MAX_VALUE;
        }
        else
            return Integer.parseInt(no);
    }
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        StringBuffer sb = new StringBuffer();
        int t = Integer.parseInt(sc.nextLine());
        while(t-->0){
            int n = Integer.parseInt(sc.nextLine());
            ArrayList<String[]> adj = new ArrayList<>(n);
            for(int i=0;i<n;++i){
                String[] input = sc.nextLine().split(" ");
                adj.add(input);
            }
            for(int k=0;k<n;++k){
                for(int i=0;i<n;++i){
                    for(int j=0;j<n;++j){
                        int cur = parseInt(adj.get(i)[j]);
                        int iToK = parseInt(adj.get(i)[k]);
                        int kToJ = parseInt(adj.get(k)[j]);
                        int infinity = Integer.MAX_VALUE;
                        if(iToK!=infinity && kToJ!=infinity && cur>iToK+kToJ)
                            adj.get(i)[j] = Integer.toString(iToK+kToJ);
                        if(parseInt(adj.get(i)[j])==infinity)
                            adj.get(i)[j]="INF";
                    }
                }
            }
            for(int i=0;i<n;++i){
                for(int j=0;j<n;++j){
                    sb.append(adj.get(i)[j]+" ");
                }
                sb.append("\n");
            }
        }
        sc.close();
        System.out.println(sb);
    }
}

第二种方法(成功通过所有测试用例):

/*package whatever //do not write package name here */

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

class GFG {
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        StringBuffer sb = new StringBuffer();
        int t = sc.nextInt();
        while(t-->0){
            int n = sc.nextInt();
            int[][] adj = new int[n][n];
            for(int i=0;i<n;++i)
                for(int j=0;j<n;++j)
                    adj[i][j] = sc.nextInt();
            for(int k=0;k<n;++k){
                for(int i=0;i<n;++i){
                    for(int j=0;j<n;++j){
                            adj[i][j] = Math.min(adj[i][j],adj[i][k]+adj[k][j]);
                    }
                }
            }
            for(int i=0;i<n;++i){
                for(int j=0;j<n;++j){
                    if(adj[i][j]==10000000)
                        sb.append("INF"+" ");
                    else
                        sb.append(adj[i][j]+" ");
                }
                sb.append("\n");
            }
        }
        sc.close();
        System.out.println(sb);
    }
}

【问题讨论】:

    标签: java performance arraylist multidimensional-array floyd-warshall


    【解决方案1】:

    简而言之,第一个解决方案的每次迭代都比第二个解决方案的每次迭代慢得多。在每次迭代中,您都执行以下操作:

    1. Integer.parseInt,这很慢。您可以查看这个答案:https://stackoverflow.com/a/22783022/12463032,以查看每个解析大约需要 60 ns,这可能比循环中的所有其他操作慢 10 倍以上。这应该是有道理的:至少parseInt 的时间与字符串的长度呈线性关系。此外,该函数并非微不足道(至少,parseInt 必须检查该数字是否为整数)。
    2. Integer.toString,这再次花费了与字符串长度成线性关系的时间。此外,它涉及对象(字符串)的创建,并且您的时间可能会因为内存处理而增加(例如 GC 在您的设置中可能无法正常工作,并且不要忘记内存分配)。

    在更高的层面上,您违反了“有效 Java”(http://wavelino.coffeecup.com/pdf/EffectiveJava.pdf) 中的第 50 条:在其他类型更合适时避免使用字符串。您对数据进行数值计算;因此,您应该将它们存储为数字。

    【讨论】:

    • 你是绝对正确的 :) 从好的方面来说,至少 OP 使用的是 StringBuffer,而不是连接原始字符串;)
    猜你喜欢
    • 2022-11-07
    • 2021-08-08
    • 2020-05-21
    • 2015-01-03
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多