针对OJ的JAVA 输入(PAT,牛客网,杭电 etc)

本文详细介绍了在Online Judge(OJ)中,如何使用Java进行输入操作,包括java.util.Scanner的键盘输入和文件读取,以及使用缓冲区的BufferedReader和最快读法StringTokenizer/StreamTokenizer。提供了多种输入场景的示例,如多行整数、自定义分隔符等,并讨论了不同读取方法的效率。

Java的输入输出主要是使用Scanner 类来实现的,这包括从键盘读取输入,从文件读取输入,向屏幕输出和写入文件。另外,为了提高速度,我们还会使用带缓冲区的读和写。

I. java.util.Scanner

1. 读取键盘输入:

首先必须引入这个包:import java.util.Scanner

然后使用 Scanner sc = new Scanner(System.in) 生成Scanner对象。System.in 在这里代指标准输入流,默认定义为键盘输入。也可以传入一个字符串,作为需要Scanner处理的对象。

import java.io.IOException;
import java.util.Scanner;

public class ScannerExample{
    public static void main(String[] args) throws IOException{
        Scanner sc = new Scanner(System.in);  // 声称Scanner对象
        System.out.println("Enter username");

        String userName = sc.nextLine();  // 读取整行作为输入,以回车键作为结束符
        System.out.println("Username is: " + userName);  // 输出读取的输入
    }
}

在OJ中,常指定主类为public Main 形式,如PTA, 牛客网等:你需要把上面的"public class ScannerExample" 换为 "public class Main"。另外, OJ还有固定的几种输入,比如

a >  多行输入,每行是一个数字(整数或者浮点数):

Input 输入数据有多组,每组占一行,由一个整数组成。
       Sample Input
       56
       67
      100
      123

import java.io.IOException;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) { //判断是否结束
            int score = sc.nextInt();
            System.out.println(score);
        }

    }
}

b> 多行输入,每行是不定数个给定类型的数字

示例: https://ac.nowcoder.com/acm/contest/320/G

输入数据有多组, 每行表示一组输入数据。每行不定有n个整数,空格隔开。(1 <= n <= 100)。

1 2 3

4 5

0 0 0 0 0

因为每行数字个数是不定的,所以只能使用while循环。我们可以先用Scanner读取输入的一行,然后再用另一个Scanner 把每一行分解到每行数字。

import java.io.IOException;
import java.util.Scanner;

public class Main {
   public static void main(String[] args) throws IOException {
        int sum;
        Scanner sc = new Scanner(System.in);

        while (sc.hasNextLine()){
            sum = 0;
            String Line = sc.nextLine();
            Scanner sc2 = new Scanner (Line);
            while (sc2.hasNextInt()){
                int currElement = sc2.nextInt();
                sum = sum + currElement;
            }
            System.out.println(sum);
        }

    }
}

c > 多行输入,单独数字的一行,或某行某数字决定了下面将有几行。

示例: http://acm.hdu.edu.cn/showproblem.php?pid=2017

输入数据有多行,第一行是一个整数n,表示测试实例的个数,后面跟着n行,每行包括一个由字母和数字组成的字符串。

Sample Input

2

asdfasdf123123asdfasdf

asdf111111111asdfasdfasdf

import java.io.IOException;
import java.util.Scanner;


public class Main {

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 0; i < n; i++) {
            String str = sc.next();
            System.out.print(str+'\n');
        }
    }
}

也可以使用 n = integer.parseInt(sc.nextLine())  (替换 int n = sc.nextInt())

d >  指定分隔符的数字,字符串识别

示例:http://acm.hdu.edu.cn/showproblem.php?pid=2005

输入数据有多组,每组占一行,数据格式为YYYY/MM/DD组成,具体参见sample input ,另外,可以向你确保所有的输入数据是合法的。

1985/1/20

2006/3/12

import java.io.IOException;
import java.util.Scanner;


public class ScannerExampleParseDate {
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        int[] dd = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        while (sc.hasNext()) {
            int days = 0;
            String str = sc.nextLine();
            String[] date = str.split("/");
            int y = Integer.parseInt(date[0]);
            int m = Integer.parseInt(date[1]);
            int d = Integer.parseInt(date[2]);
            if ((y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) && m > 2) days++;
            days += d;
            for (int i = 0; i < m; i++) {
                days += dd[i];
            }
            System.out.println(days);
        }
    }
}

e> 多行输入,行内数据类型不全相同,但位置相同

示例:http://acm.hdu.edu.cn/showproblem.php?pid=1170

输入:Input contains multiple test cases. The first line of the input is a single integer T (0<T<1000) which is the number of test cases. T test cases follow. Each test case contains a char C (+,-,*, /) and two integers A and B(0<A,B<10000).Of course, we all know that A and B are operands and C is an operator.

Sample Input

4

+ 1 2

- 1 2

* 1 2

/ 1 2

import java.io.IOException;
import java.util.Scanner;

public class ScannerExampleVariesTypeInOneLine {
    public static void main(String[] args) throws IOException {
        Scanner sc =new Scanner(System.in);
        int n = sc.nextInt();
        for(int i=0;i<n;i++){
            String op = sc.next();
            int a = sc.nextInt();
            int b = sc.nextInt();
            if(op.charAt(0)=='+'){
                System.out.println(a+b);
            }else if(op.charAt(0)=='-'){
                System.out.println(a-b);
            }else if(op.charAt(0)=='*'){
                System.out.println(a*b);
            }else if(op.charAt(0)=='/'){
                if(a % b == 0) System.out.println(a / b);
                else System.out.format("%.2f", (a / (1.0*b))).println();
            }
        }
    }

}

f> 创建数组或者动态扩增ArrayList来存储读入的数据

当给定大小时,可以直接创建数组

int n = sc.nextInt();
int[] arr = new int[n];//动态创建大小为n的数组
for(int i = 0; i < n; i++){
    arr[i] = sc.nextInt();
}

当给定的大小不定时,使用ArrayList动态扩增

List<String> strList = new ArrayList<String>();//Java 7中可以List<String> strList = new ArrayList<>();
while(sc.hasNextLine()){
    strList.add(sc.nextLine());
}

//遍历输出列表中的内容
for (int i = 0; i < strList.size(); i++) {
    String str = strList.get(i);
    System.out.println(str);
}
//或者
for(String e: strList){
    System.out.println(e);
}

 

2. 读取文件

Scanner 类同样可以读取文件,只是这时候需要传入一个文件对象即可。基本格式为:

import java.io.File
import java.util.Scanner
import java.io.IOException

省略其他代码

File infile = new File(src/resource/test.txt);
Scanner sc = new Scanner(infile);


省略其他代码

示例中使用的是在java 工程中的相对路径:

这里写图片描述

我们也可以使用绝对路径:

File infile = new File("C:\project\infile.txt");

读取文件如果有固定格式,那么按照给定格式解析即可。否则应该一次一行的读取,使用nextLine()方法。

示例:从一个文件中读取数据,需要将奇数行、偶数行的数据分别存放到不同的数组中,而且,奇数行获取偶数行中每个数据中间空格数不同。

数据格式:

23 23           32     32 43         21 23        3   43

 

2   43  23 1 2            3

 

9              8 1       2  3

3 4 88 99          99

import java.io.File;
import java.util.Scanner;

// 相对文件读取处理
public class FileReader {

    public static void main(String[] args) throws Exception {
        fileReader("src/resource/test.txt");
    }

    public static void fileReader(String fileName) throws Exception {

        File file = new File(fileName);
        Scanner sc = new Scanner(file);

        int rows = 1; // 记录行数

        String[] odd = new String[40]; // 奇数行数据
        String[] even = new String[40]; // 偶数行数据
        while (sc.hasNextLine()) {
            if ((rows % 2) == 1) { // 奇数行
                odd = sc.nextLine()***.split("\\s{1,}")***;  // split("\\2{1,}");不论字符中间有多少个空格都当作一个空格处理
                System.out.println("奇数行:" + rows);
                for (int i = 0; i < odd.length; i++) {
                    System.out.println(odd[i]);
                }
            } else if ((rows % 2) == 0) { // 偶数行
                even = sc.nextLine().***split("\\s{1,}***");
                System.out.println("偶数行:" + rows);
                for (int i = 0; i < even.length; i++) {
                    System.out.println(even[i]);
                }
            }
            rows++;
        }
        sc.close();
    }

}

 

II. 使用缓冲区读: BufferedReader/ BufferedWriter

import java.io.BufferedReader;
import java.io.Reader;

public class Main {
    public static void main(String[] args) throws Exception {
        char c ;
        BufferedReader bd = new BufferedReader(new InputStreamReader(System.in));

        //read(),读入一个字符
        System.out.println("input a char,end with 'e'");
        do {
            c = (char)bd.read() ;
            System.out.println(c);
        }while(c != 'e') ;

        //readLine(),读入每行的文本数据(包括空格)
        String str=null ;
        System.out.println("string end with 'end'");
        do {
            str = bd.readLine() ;
            System.out.println(str);
        }while(!str.equals("end")) ;
    } 
}

 

III 最快的读法: java.util.StringTokenizer / java.io.StreamTokenizer

 

StringTokenizer st = new StringTokenizer("this is in china") ;//默认是空格为分割符
        while(st.hasMoreTokens()) {
            System.out.println(st.nextToken());
        }
        StringTokenizer st1 = new StringTokenizer("this is my ida,and this is also yours"," ,") ;   //自定义分割符
    while(st1.hasMoreTokens()) {
            System.out.println(st1.nextToken());
        }
StreamTokenizer st = new StreamTokenizer(new BufferedReader
                (new InputStreamReader(System.in))) ;
        st.nextToken() ;//获得令牌
        String str = st.sval ;//取出令牌,sval为该类的静态常量
        //表示一个文本,以制表符,换行符,空格为分割符
        st.nextToken() ;
        int a = (int) st.nval ;//nval为该类的静态常量,表示读取的是个数字
        System.out.println(str);
        System.out.println(a);

 

参考资料:

 

1. http://acm.hdu.edu.cn/

2. https://www.cnblogs.com/zhrb/p/6347738.html

3. https://www.acwing.com/blog/content/279/  (三种读取方法的时间比较)

4. https://blog.csdn.net/shijiebei2009/article/details/17305223

5. https://www.jianshu.com/p/fa235c29fbea

6. https://blog.csdn.net/sunyanxiong123/article/details/75212717

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值