Scanner和BufferReader的效率问题
先给出一道题,测试平台是Acwing, 这道题是腾讯2019年春招提前批笔试第二题。题目不难,但是如果不注意细节,很容易TLE(超时)
https://www.acwing.com/problem/content/570/
下面的做法是用JAVA scanner依次读入输入数据,但这样做的效率较低,会直接导致TLE:
1 import java.util.Scanner; 2 3 public class Main { 4 public static void main(String[] args) { 5 Scanner in = new Scanner(System.in); 6 int n = in.nextInt(); 7 for(int i = 1; i <= n; i++){ 8 int l = in.nextInt(); 9 int r = in.nextInt(); 10 11 int sum1 = 0; 12 int sum2 = 0; 13 if(r%2 == 0) 14 sum1 = r/2; 15 else 16 sum1 = r/2-r; 17 if((l-1)%2==0) 18 sum2 = l/2; 19 else 20 sum2 = l/2-l; 21 22 System.out.println(sum1-sum2); 23 } 24 } 25 }
结果如下所示,在读入超过10万行的输入的时候直接超时
好的做法是使用BufferedReader来读输入,以下代码AC
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 5 6 public class Main { 7 8 9 public static void main(String[] args) throws IOException { 10 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 11 int q = Integer.valueOf(br.readLine()); 12 while (q-- > 0) { 13 String[] parts = br.readLine().split(" "); 14 int l = Integer.valueOf(parts[0]); 15 int r = Integer.valueOf(parts[1]); 16 17 int k = (r-l+1)/2; 18 int res = 0; 19 if(l%2==0) 20 res = -k; 21 else 22 res = k; 23 if((r-l+1)%2==1){ 24 if(r%2==0) 25 res += r; 26 else 27 res -=r; 28 } 29 System.out.println(res); 30 } 31 } 32 }
代码通过:
可能有人觉得Scanner我也可以使用整行读入的方式呀,可是这样仍然会TLE:
1 import java.util.Scanner; 2 3 public class Main { 4 public static void main(String[] args) { 5 Scanner in = new Scanner(System.in); 6 int n = in.nextInt();//Scanner读入一个int后, 读入指针仍然停留在该行 7 in.nextLine();//必须消耗掉上一行的所有数据,读到\n,才能去读下一行,因此这里用nextLine()消耗掉上一行的末尾 8 for(int i = 1; i <= n; i++){ 9 String[] parts = in.nextLine().split(" "); 10 int l = Integer.valueOf(parts[0]); 11 int r = Integer.valueOf(parts[1]); 12 13 14 int k = (r-l+1)/2; 15 int res = 0; 16 if(l%2==0) 17 res = -k; 18 else 19 res = k; 20 if((r-l+1)%2==1){ 21 if(r%2==0) 22 res += r; 23 else 24 res -=r; 25 } 26 System.out.println(res); 27 } 28 } 29 }
说明Scanner在读入大量数据的时候确实不如BufferedReader的效率高!
有人作了测试:
从测试结果来看,Scanner的平均耗时是BufferedReader的10倍左右.
在这里贴上关于Scanner和BufferedReader的对比分析。
BufferedReader可以用来读取文件或者接收来自键盘(控制台)的信息。它比Scanner更加快捷,能够大幅度缩短程序运行时间。它下面的readline()方法可以一次性读取一行文字(String),非常方便。需要注意的是,使用BufferedReader对象的readLine()方法必须处理java.io.IOException异常(Exception)。以及,在使用完BufferredReader以后,需要用close()方法关闭流。
可以从源码上看看这两者之间的区别
【Java8源码分析】IO包-Reader、BufferedReader和Scanner总结
这里面有点类似与,C++提供的cin输入流的效率远不如C的scanf函数效率高
TALK IS CHEAP, SHOW ME THE CODE