ACM赛制java输入输出
主要在leetcode上以核心代码模式刷题如果突然切换到ACM模式会很不习惯, 但是这也是在面试过程中可能会考察的
因此掌握ACM赛制java的基本输入输出操作十分必要
Scanner
和 System.out.print
在最开始会工作得很好,但是在处理更大的输入的时候会降低效率,因此我们会需要使用一些方法来提高 IO 速度。
- 总计 Java 算法的 ACM 模式需要注意的地方
输入输出模板
使用 Kattio + StringTokenizer 作为输入
最常用的方法之一是使用来自 Kattis 的 Kattio.java 来提高 IO 效率。
- 这个方法会将
StringTokenizer
与 PrintWriter
包装在一个类中方便使用。
而在具体进行解题的时候(假如赛会/组织方允许)可以直接使用这个模板。下方即为应包含在代码中的 IO 模板,由于 Kattis 的原 Kattio 包含一些并不常用的功能,下方的模板经过了一些调整(原 Kattio 使用 MIT 作为协议)。
而下方代码简单展示了 Kattio 的使用:
Kattio.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Kattio extends PrintWriter { private BufferedReader r; private StringTokenizer st; public Kattio() { this(System.in, System.out); } public Kattio(InputStream i, OutputStream o) { super(o); r = new BufferedReader(new InputStreamReader(i)); } public Kattio(String intput, String output) throws IOException { super(output); r = new BufferedReader(new FileReader(intput)); } public String next() { try { while (st == null || !st.hasMoreTokens()) st = new StringTokenizer(r.readLine()); return st.nextToken(); } catch (Exception e) {} return null; } public int nextInt() { return Integer.parseInt(next()); } public double nextDouble() { return Double.parseDouble(next()); } public long nextLong() { return Long.parseLong(next()); } }
|
简单使用:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Test { public static void main(String[] args) { Kattio io = new Kattio(); String str = io.next(); int num = io.nextInt(); io.println("Result"); io.close(); } }
|
使用 StreamTokenizer 作为输入
在某些情况使用 StringTokenizer
会导致 ==MLE==(Memory Limit Exceeded
,超过内存上限),
此时我们需要使用 StreamTokenizer
作为输入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import java.io.*; public class Main { public static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in), 32768)); public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); public static double nextDouble() throws IOException { in.nextToken(); return in.nval; } public static float nextFloat() throws IOException { in.nextToken(); return (float)in.nval; } public static int nextInt() throws IOException { in.nextToken(); return (int)in.nval; } public static String next() throws IOException { return in.sval; } public static long nextLong() throws Exception { in.nextToken(); return (long)in.nval;} public static void main(String[] args) throws Exception { int n = nextInt(); out.println(n); out.close(); } }
|
两者对比
Kattio + StringTokenizer
的方法与 StreamTokenizer
的方法之间的分析与对比
StreamTokenizer
相较于StringTokenizer
使用的内存较少,当 Java 标程 MLE 时可以尝试使用StreamTokenizer
,但是StreamTokenizer
会丢失精度,读入部分数据时会出现问题;
StreamTokenizer
源码存在 Type
,该 Type
根据你输入内容来决定类型,倘若你输入类似于 123oi
以 数字开头 的字符串,他会强制认为你的类型是 double
类型,因此在读入中以 double
类型去读 String
类型便会抛出异常;
StreamTokenizer
在读入 1e14
以上大小的数字会丢失精度;
- 在使用
PrintWriter
情况下,需注意在程序结束最后 close()
关闭输出流或在需要输出的时候使用 flush()
清除缓冲区,否则内容将不会被写入到控制台/文件中。
Kattio
是继承自 PrintWriter
类,自身对象具有了 PrintWriter
的功能,因此可以直接调用 PrintWriter
类的函数输出,同时将 StringTokenizer
作为了自身的成员变量来修改。而第二种 Main
是同时将 StreamTokenizer
与 PrintWriter
作为了自身的成员变量,因此在使用上有些许差距。
综上所述,在大部分情况下,StringTokenizer
的使用处境要优越于 StreamTokenizer
,在极端 MLE 的情况下可以尝试 StreamTokenizer
,同时 int
范围以上的数据 StreamTokenizer
处理是无能为力的。
结论 : 优先使用 Kattio
题目示例
输入两个整数 a, b,输出它们的和
java语言程序范例
1 2 3 4 5 6 7 8 9
| import java.io.*; import java.util.*; public class Main { public static void main(String args[]) throws Exception { Scanner cin=new Scanner(System.in); int a = cin.nextInt(), b = cin.nextInt(); System.out.println(a+b); } }
|
本题java代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import java.io.*; import java.util.StringTokenizer;
public class Main { public static void main(String[] args) throws Exception{ Kattio io = new Kattio(); long a=io.nextLong(); long b=io.nextLong(); io.print(a+b); io.close(); } } class Kattio extends PrintWriter { private BufferedReader r; private StringTokenizer st; public Kattio() { this(System.in, System.out); } public Kattio(InputStream i, OutputStream o) { super(o); r = new BufferedReader(new InputStreamReader(i)); } public Kattio(String intput, String output) throws IOException { super(output); r = new BufferedReader(new FileReader(intput)); } public String next() { try { while (st == null || !st.hasMoreTokens()) st = new StringTokenizer(r.readLine()); return st.nextToken(); } catch (Exception e) {} return null; } public int nextInt() { return Integer.parseInt(next()); } public double nextDouble() { return Double.parseDouble(next()); } public long nextLong() { return Long.parseLong(next()); } }
|
注意点
-
类名称必须采用public class Main
方式命名
-
在提交java代码的时候, 不要带上package
-
多行数据处理
1 2 3 4
| static Scanner in = new Scanner(System.in); while(in.hasNextInt())
while(in.hasNext())
|
参考网站