ACM模式Java输入输出处理完全指南
ACM模式Java输入输出处理完全指南
难度: 基础到进阶
标签: ACM, Java, 输入输出, 算法竞赛, 编程技巧
适用场景: 算法竞赛、笔试面试、在线编程平台
📝 概述
ACM模式是算法竞赛中常见的编程模式,与LeetCode的函数式编程不同,ACM模式需要手动处理输入输出。本指南涵盖Java中各种常见的输入输出处理模式。
💭 基础知识
初步理解
ACM模式要求程序能够:
- 读取多组测试数据
- 处理不同格式的输入
- 按照指定格式输出结果
- 处理输入结束条件
常用类和方法
Scanner类:最常用的输入处理类BufferedReader类:高效读取大量数据StringTokenizer类:字符串分割System.out.print()和System.out.println():输出
🎯 常见输入输出模式
模式一:固定数量输入
场景描述:
输入第一行是测试用例数量n,后面跟着n行数据。
输入样例:1
2
3
43
1 2
3 4
5 6
输出样例:1
2
33
7
11
代码实现(使用Scanner):
1 | import java.util.Scanner; |
模式二:直到特定值结束
场景描述:
输入多组数据,直到遇到特定值(如0)时结束。
输入样例:1
2
3
45 3
10 20
0 0
15 25
输出样例:1
28
30
代码实现:
1 | import java.util.Scanner; |
更多测试用例:
立即结束:
1
0 0
输出:(无输出)
负数处理:
1
2
3-5 10
3 -7
0 0输出:
1
25
-4单组数据:
1
2100 200
0 0输出:
1
300
模式三:直到文件末尾
场景描述:
输入多组数据,直到文件末尾(EOF)。
输入样例:1
2
31 2
3 4
5 6
输出样例:1
2
33
7
11
代码实现:
1 | import java.util.Scanner; |
更多测试用例:
单行输入:
1
42 58
输出:
1
100
多行混合数据:
1
2
3
410 20
30 40
50 60
70 80输出:
1
2
3
430
70
110
150实际应用场景(文件重定向):
1
2# 将数据保存在input.txt文件中
java Main < input.txt
模式四:字符串处理
场景描述:
处理包含空格的字符串输入。
输入样例:1
2
3
43
Hello world Java programming
ACM algorithm competition
Data structures and algorithms
输出样例:1
2
3Word count: 4
Word count: 3
Word count: 4
代码实现:
1 | import java.util.Scanner; |
⚠️ 重要注意事项:Scanner的nextLine()陷阱
Q1: 为什么 nextLine() 在 nextInt() 或 next() 之后不生效?
nextInt() 或 next() 不会读取换行符,导致后续的 nextLine() 直接读取到空行。
解决方法:在 nextInt() 或 next() 后加一个 nextLine() 来消耗换行符。
错误示例:1
2
3
4
5
6Scanner sc = new Scanner(System.in);
System.out.print("输入数字:");
int num = sc.nextInt(); // 读取数字,但不读取换行符
System.out.print("输入字符串:");
String str = sc.nextLine(); // 直接读取换行符,导致 str 为空
System.out.println("数字:" + num + ",字符串:" + str);
输入:1
2123
Hello
输出:1
数字:123,字符串:
nextLine() 读取了 nextInt() 留下的换行符,导致 str 为空。
修正方法:1
2
3
4
5
6
7Scanner sc = new Scanner(System.in);
System.out.print("输入数字:");
int num = sc.nextInt();
sc.nextLine(); // 消耗换行符
System.out.print("输入字符串:");
String str = sc.nextLine(); // 正确读取
System.out.println("数字:" + num + ",字符串:" + str);
输出:1
数字:123,字符串:Hello
更多测试用例:
多空格处理(改进版本):
1
2// 改进版本:使用正则表达式处理多个空格
String[] words = line.split("\\s+");空字符串测试:
1
2
32
Hello world输出:
1
2Word count: 1
Word count: 2特殊字符处理:
1
2
32
Hello, world!
Java-programming@2025输出:
1
2Word count: 2
Word count: 1
模式五:高性能输入(BufferedReader)
场景描述:
处理大量数据时,需要更高效的输入方式。
输入样例:1
2
3
4
54
100 200
50 75
300 400
25 35
输出样例:1
2
3
4300
125
700
60
代码实现:
1 | import java.io.*; |
性能对比测试:
- 大数据量测试(10万行):性能数据:
1
2
3
4
5
6100000
1 2
3 4
5 6
...
[继续99997行]- Scanner: 约500-800ms
- BufferedReader: 约100-200ms
- 性能提升:4-5倍
适用场景:
- n > 10000时推荐使用
- 时间限制严格的竞赛题目
- 需要处理大规模输入数据
模式六:二维数组输入
场景描述:
输入二维数组或矩阵。
输入样例:1
2
3
43 4
1 2 3 4
5 6 7 8
9 10 11 12
输出样例:1
Matrix sum: 78
代码实现:
1 | import java.util.Scanner; |
动态数组实现(使用ArrayList):
1 | import java.util.ArrayList; |
更多测试用例:
正方形矩阵:
1
2
3
43 3
1 2 3
4 5 6
7 8 9输出:
1
Matrix sum: 45
单行矩阵:
1
21 5
10 20 30 40 50输出:
1
Matrix sum: 150
单列矩阵:
1
2
3
4
54 1
1
2
3
4输出:
1
Matrix sum: 10
边界情况(1×1矩阵):
1
21 1
42输出:
1
Matrix sum: 42
模式七:不定长数组输入
场景描述:
每行输入不定数量的数字。
输入样例:1
2
3
41 2 3 4 5
10 20 30 40
100
输出样例:1
2
315
100
100
代码实现:
方法1:使用 Scanner
1 | import java.util.Scanner; |
方法2:使用 Scanner嵌套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
27import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String line;
long sum;
while (sc.hasNextLine()) { // 持续读取每一行,直到输入结束
line = sc.nextLine();
if (line.trim().isEmpty()) { // 如果遇到空行,跳过
continue;
}
Scanner lineScanner = new Scanner(line); // 创建新的Scanner读取每行的数据
sum = 0;
while (lineScanner.hasNextLong()) { // 逐个读取这一行的整数
long num = lineScanner.nextLong();
sum += num; // 将读取的整数累加到 sum 中
}
System.out.println(sum); // 输出这一行所有整数的和
lineScanner.close();
}
sc.close(); // 关闭Scanner
}
}
更多测试用例:
多空格处理:
1
5 10 15 20
输出:
1
50
单行单数:
1
42
输出:
1
42
负数处理:
1
-10 20 -5 15
输出:
1
20
空行结束:
1
2
31 2 3
4 5 6输出:
1
26
15
模式八:多组测试用例(每组不同格式)
场景描述:
复杂的输入格式,每组测试用例可能包含不同类型的数据。
输入样例:1
2
3
4
5
6
7
8
9
103
5
1 2 3 4 5
sum 0
4
10 20 30 40
max 0
6
1 2 3 4 5 3
count 3
输出样例:1
2
3Case #1: 15
Case #2: 40
Case #3: 2
代码实现:
1 | import java.util.Scanner; |
更多测试用例:
查找操作:
1
2
3
4
5
6
72
5
10 20 30 40 50
find 30
3
1 2 3
find 5输出:
1
2Case #1: 2
Case #2: -1单元素数组:
1
2
3
41
1
42
sum 0输出:
1
Case #1: 42
边界测试:
1
2
3
41
3
-5 0 5
max 0输出:
1
Case #1: 5
🚀 关键要点
核心概念
- 输入流处理:理解如何读取不同类型的输入数据
- 循环控制:掌握各种输入结束条件的处理
- 字符串分割:熟练使用split()和StringTokenizer
- 异常处理:合理处理输入异常
常见陷阱
- 换行符处理:nextInt()后使用nextLine()需要特别注意
- 空格处理:字符串输入中的空格分割问题
- EOF判断:正确处理文件结束条件
- 性能问题:大量数据时选择合适的输入方式
性能优化建议
- 小数据量:使用Scanner,代码简洁
- 大数据量:使用BufferedReader + StringTokenizer
- 超大数组:考虑使用快速输入输出类
📚 实战练习
练习题1:A + B Problem
描述:计算两个数的和,直到文件结束。
输入:多行,每行两个整数
输出:每行输出对应的和
练习题2:字符串统计
描述:统计输入字符串中各个字符的出现次数。
输入:第一行是测试用例数量,后面是字符串
输出:每个字符串的字符统计结果
练习题3:矩阵运算
描述:实现矩阵的转置操作。
输入:矩阵的行数和列数,然后是矩阵元素
输出:转置后的矩阵
🏷️ 相关标签
- ACM
- Java
- 输入输出
- 算法竞赛
- 编程技巧
- 笔试面试
📖 参考资料
最后更新:2025-01-15






