竞争性的编程和输入

时间:2011-03-24 18:33:02

标签: java io

你好 我正在练习一场竞争性的比赛,几周之后就会在我的教职员工中,因此我遇到了一个小问题。
竞争限制了java.io。* 的使用(IOException除外)
我需要读取(从stdin)输入,每个测试用例用空行分隔。测试用例结束 - 找到EOF时。 我需要找到一种从IO获取数据的方法,而不使用java.io 到目前为止,我得到了这个(有效) - 它返回一个包含每个测试用例的字符串,当我没有测试用例时返回null。

public static String getInput() throws IOException {
    int curr=0;
    int prev=0;
    StringBuilder sb = new StringBuilder();
    while (true) {
        curr = System.in.read();
        if (curr == -1) { 
            return null; //end of data
        }
        if (curr == '\r') {
            curr = System.in.read();
        }
        if (curr == prev && curr == '\n') {
            return sb.toString(); //end of test case
        } //else:
        sb = sb.append((char)curr);
        prev = curr;
    }
}

性能(对于IO)被忽略了,所以我不在乎每次只读一个字节。
问题:是否有更优雅(这意味着 - 更短更快的代码)方式来实现同样的目标?

4 个答案:

答案 0 :(得分:5)

事实上,在竞争性编程中,有几种方法可以用Java处理输入。

方法1:使用java.util.Scanner

这是读取输入的最简单方法,它也非常简单易用。如果你有大量的输入,它可能会很慢。如果您的程序持续获得TLE(超出时间限制),但您的程序具有正确的时间复杂度,请尝试使用第二种或第三种方法读取输入。

初始化Scanner sc = new Scanner(System.in);

读取整数:int n = sc.nextInt();

方法2:使用java.io.BufferedReader

如果输入量很大,并且问题的时间限制很严格,请使用此选项。它确实需要更多的工作,包括用空格分割输入,或使用Integer.parseInt(str);从输入中提取整数。

您可以在此处找到速度比较https://www.cpe.ku.ac.th/~jim/java-io.html

初始化:BufferedReader reader = new BufferedReader(System.in);

读取整数:int n = Integer.parseInt(reader.readLine());

方法3:使用自定义阅读器直接从FileDescriptor阅读

这种方法是Java中最快的方法。它确实需要大量的工作,包括实现阅读器,以及在出现任何问题时进行调试。如果时间限制严格,并且允许您将代码带入竞争对手,请使用此方法。测试此方法比第二种方法快得多,但它通常不会为您提供优势,因为它只是BufferedReader方法速度的2倍。

这是我朋友写的这种方法的一种实现方式: https://github.com/jackyliao123/contest-programming/blob/master/Utils/FastScanner.java

阅读器的使用实际上取决于您对阅读器的实现。建议保留一份有效保证的读者副本,因为你在比赛中想要的最后一件事是拥有一个不起作用的读者并调试你的其余程序,认为那里有一些错误。

希望这对您的比赛有所帮助和祝福!

答案 1 :(得分:1)

您可以尝试以下操作,并通过包装System.in来提高效率。

public static String readLine() throws IOException {
    StringBuilder sb = new StringBuilder();
    for (int ch; (ch = System.in.read()) > 0;)
        if (ch == '\r') continue;
        else if (ch == '\n') break;
        else sb.append(ch);
    return sb.toString();
}

编辑:在Oracle JVM上,System.in是一个BufferedInputStream,它包装了一个包装FileDescriptor的FileInputStream。所有这些都在java.io。

答案 2 :(得分:1)

如果允许java.util.Scanner,您可以尝试使用java.util课程。它有一些有用的方法可以根据需要读取一行,一个令牌甚至一个数字。但它比BufferedReader慢,可能比直接使用System.in.read()慢。

由于System.in实现了InputStream接口,因此使用System.in.read(byte[] b)读取输入也可能是一些加速。这样你就可以一次读取一堆字节而不是一个字节,这应该更快。但是在比赛期间必须编码和调试它的复杂性可能不值得。

编辑: 在网上搜索时,我发现有人在UVa forum时讨论使用System.in.read(byte[] b),当时UVa有可怕的Java支持。

答案 3 :(得分:1)

您可以使用扫描仪

import java.util.Scanner;//put this above the class
Scanner scanner = new Scanner(System.in); //this creates the scanner
int input = scanner.nextInt();

.nextInt() 接受整数
.nextLine() 接受字符串