前言:
因为Java语言的运行缓慢,因此在OJ中Java需要使用比C/C++更多的运行时间和运行内存,但是依然比较容易超时,因此在oj中几乎没有人使用Java来作为编程语言。
但是,如果你执着于使用Java语言,不妨记住以下的优化策略。
1. 替换输入
不要使用Scanner作为输入方式,使用BufferedReader作为替换,并在结束输入后尽早将其close()掉。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//...
br.close();
之所以替换掉是因为Scanner输入运行及其缓慢,以下表格展示了输入的运行效率(表格来源:Faster Input for Java):
Table 1. Time to read 10,000,000 int values from file:
Input Method | Time (sec) |
---|---|
scanf(“%d”, &arg) | 3.78 |
Scanner.parseInt() | 29.52 |
BufferedReader + inline Integer.parseInt | 2.89 |
BufferedReader + Reader.nextInt method | 3.01 |
Table 2. Time to read 10,000,000 double values from file:
Input Method | Time (sec) |
---|---|
scanf(“%lf”, &arg) | 11.9 |
Scanner.parseDouble() | 66.86 |
BufferedReader + inline Double.parseDouble | 3.06 |
BufferedReader + Reader.nextDouble method | 3.14 |
同时,Faster Input for Java 利用StringTokenizer
提供了封装好的输入类:
/** Class for buffered reading int and double values */
class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
/** call this method to initialize reader for InputStream */
static void init(InputStream input) {
reader = new BufferedReader(
new InputStreamReader(input) );
tokenizer = new StringTokenizer("");
}
/** get next word */
static String next() throws IOException {
while ( ! tokenizer.hasMoreTokens() ) {
//TODO add check for eof if necessary
tokenizer = new StringTokenizer(
reader.readLine() );
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt( next() );
}
static double nextDouble() throws IOException {
return Double.parseDouble( next() );
}
}
使用时如下即可:
Reader.init( System.in ); // connect Reader to an input stream
double x = Reader.nextDouble();
int n = Reader.nextInt();
2. 替换输出
注:如果编译环境为JDK1.8,此条可忽略,因为JDK1.8中将”+”号的默认实现修改为了StringBuilder!
当你的输出是由多个变量拼接而成时,例如:
Sysyem.out.println("Student: " + name + ",age: " + age);
将其替换成StringBuilder
,并使用append()方法拼接,即:
StringBuilder sb = new StringBuilder();
sb.append("Student: ").append(name).append(",age: ").append(age);
System.out.println(sb);
这是因为String对象为不可变对象,一旦被创建,就不能修改它的值。对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去。
而StringBuilder不会创建新的对象,实际是指针的移动。