竞争性编程和输入

发布于 2024-10-26 11:32:22 字数 888 浏览 6 评论 0原文


我正在为几周后在我的学院举行的竞技比赛进行练习,因此我遇到了一个小问题。
比赛限制了java.io的使用。*(IOException除外...)
我需要(从标准输入)读取输入,每个测试用例都用空行分隔。测试用例结束 - 当发现 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)被忽略了,所以我不在乎每次只读取一个字节。
问题:是否有更优雅(编码更短、速度更快)的方法来实现相同的目标?

I'm practicing for a competitive tournament that will be in my faculty in a few weeks, and thus I encountered a small problem.

The competition restricted the use of java.io.* (except IOException...)

I need to read (from stdin) input, each test case is separated with a blank line. end of test cases - when EOF is found.

I need to find a way to get data from IO, without using java.io

so far, I got this (which works) - it returns a string containing each test case, and null when I'm out of test cases.

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;
    }
}

performance (for the IO) is neglected, so I don't care I read only one byte every time.

Question: Is there a more elegant (shorter and faster to code) way to achieve the same thing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

手长情犹 2024-11-02 11:32:22

事实上,在竞争性编程中,有几种方法可以处理 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

读取器的使用实际上取决于您的读取器的实现。建议保留一份可以保证正常工作的阅读器副本,因为在竞赛中您最不想看到的就是拥有一个无法正常工作的阅读器并调试程序的其余部分,认为那里存在一些错误。

希望这对您有所帮助,并祝您比赛顺利!

In fact, there are a few ways that you can process input in Java in competitive programming.

Approach 1: Using java.util.Scanner

This is the simplest way to read input, and it is also really straightforward to use. It can be slow if you have a huge amount of input. If your program keeps getting TLE (Time Limit Exceeded), but your program has the correct time complexity, try reading input with the second or third approach.

Initialization Scanner sc = new Scanner(System.in);

Reading an integer: int n = sc.nextInt();
Approach 2: Using java.io.BufferedReader

Use this one if there is a huge amount of input, and when the time limit of the problem is strict. It does require some more work, involving splitting the input by spaces, or using Integer.parseInt(str); to extract integers from the input.

You can find a speed comparison here https://www.cpe.ku.ac.th/~jim/java-io.html

Initialization: BufferedReader reader = new BufferedReader(System.in);

Reading an integer: int n = Integer.parseInt(reader.readLine());

Approach 3: Reading directly from FileDescriptor using custom reader

This approach is the fastest approach possible in Java. It does require a lot of work, including implementing the reader, as well as debugging should any problems arise. Use this approach if the time limit is strict and if you are allowed to bring code into the competition. This method is tested to be much faster than the second approach, but it would not usually provide you with an advantage since it is only about 2x the speed of the BufferedReader approach.

This is one implementation of such an approach written by my friend:
https://github.com/jackyliao123/contest-programming/blob/master/Utils/FastScanner.java

The usage of the reader really depends on your implementation of the reader. It is suggested to maintain one copy of the reader that is somewhat guaranteed to work, because the last thing you want in a contest is having a non-functional reader and debugging the rest of your program, thinking there are some bugs there.

Hope this helps and best wishes on your competition!

白昼 2024-11-02 11:32:22

您可以尝试以下方法,并通过包装 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,它包装了一个FileInputStream,而FileInputStream又包装了一个FileDescriptor。所有这些都在java.io中。

You could try the following and make it efficient by wrapping the 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();
}

EDIT: On Oracle JVM, System.in is a BufferedInputStream which wraps a FileInputStream which wraps a FileDescriptor. All these are in java.io.

无远思近则忧 2024-11-02 11:32:22

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

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

编辑:
在网上搜索时,我发现有人在 UVa 论坛 那时 UVa 对 Java 的支持很糟糕。

You can try using the java.util.Scanner class if java.util is allowed. It has useful methods for reading in a line, a token or even a number as needed. But it is slower than BufferedReader and possibly slower than using System.in.read() directly.

Since System.in implements the InputStream interface, it might also be some speedup to use System.in.read(byte[] b) to read in the input. This way you can read in a bunch of bytes at a time instead of just the one, which should be faster. But the added complexity of having to code and debug it during the contest might not be worth it.

Edit:
Searching the web I found someone discussing using System.in.read(byte[] b) in the UVa forum back when UVa had terrible Java support.

云醉月微眠 2024-11-02 11:32:22

您可以使用扫描仪

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() 接受字符串

You can use a scanner

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

.nextInt() takes integers
.nextLine() takes strings

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文