java快速输入输出

主要记录在PTA时经常遇到的超时问题,基本都是由于Scanner耗时过长导致的,至于输出的话基本就是用

static PrintWriter out = new PrintWriter(System.out);

输出的时候有多种方法,可以用printf,也可以用println,看个人需要了。输出完的时候记得要加上这段,不然没办法打印。

out.flush();	//关闭输出流

后面主要介绍的都是快读的方法。

StreamTokenzier类

这个类基本可以应付大部分快读问题,而且由于经常遇到的是组合输入,所以用这种方法会比较多。这个方法也是笔者目前使用的效率最高的快读方法。

但使用这个类的时候要注意一个问题,就是它读取的时候会自动解析空格字母数字字符串引号注释字符 ,在读取字符串的时候需要注意这种情况,以免丢失必要的数据。除此之外,在解析数字时,其默认是以double进行解读,所以可能会在转换成long型的时候出现误差,需要多加注意。

初始化方法

static StreamTokenizer sc =new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

输入方法

sc.nextToken()	//读取前都要加,用于当前输入流的下一个标记
//字符串
String s = sc.sval;
//int型数据
int a = (int)sc.nval;
//double型数据
double d = sc.nval;
//long型数据
long l = (long)sc.nval;	
long l = Long.parseLong(sc.sval); //如果数据非常大的时候导致精度丢失,建议先读取字符串再转为long

StreamTokenizer的基本方法

由于会自动对一些字符进行解析,在读取纯数字的字符串的时候就有很多不便,为解决这个问题先介绍一些基本方法。

  • commenChar(int ch) - 指定某个字符为注释字符,此字符之后直到行结尾都被stream tokenizer忽略。
  • eolIsSignificant(boolean flag) -** 决定一个行结束符是否被当作一个基本的符号处理,如果是true,则被当作一个基本符号,不当作普通的分隔符,如果是false,则保持原义,即当作普通的分隔符。
  • lineno() - 返回当前流所在的行号。
  • lowerCaseMode(boolean flag) - 决定是否读取一个单词时是否转变成小写。
  • nextToken() - 分析下一个。
  • ordinaryChar(int ch) - 指定字符在这个tokenizer中保持原义,即只会把当前字符认为普通的字符,不会有其他的语义。
  • ordinaryChars(int low, int hi) - 指定范围内的字符保持语义,同上
  • parseNumbers() - 当stream tokenizer遭遇到一个单词为双精度的浮点数时,会把它当作一个数字,而不是一个单词。
  • pushBack() - 回退,会引起下一个nextToken方法返回当前值。
  • quoteChar(int ch) - 指定当前字符为当前tokenizer中的分隔符,在两个符号之间被当作一个字符串解析。
  • resetSyntax() - 重置语法表使所有的字符都被认为是“ordinary”。
  • slashSlashComments(boolean flag) - 如果为true,则//之间的都被认为是注释,反之,不是。
  • slashStartComments(boolean flag) - 如果为true,则//之后到行结尾的所有都被认为是注释,反之,不是。
  • whitespaceChars(int low, int hi) - 字符low与hi之间的所有字符都被当作为空格符,即被认识为tokenzier的分隔符。
  • wordChars(int low, int hi) - 字符low与hi之间的所有字符都被当作为单词的要素。 一个单词是由一个单词要素后面跟着0个或者更多个单词要素或者数字要素。

读取纯数字字符串

前面提到了读纯数字字符串的时候会被识别成数字,读不出来,这个时候就需要提前将数字指定成单词了。方法如下:

sc.ordinaryChars('0','9');	//将0-9认作普通的字符
sc.wordChars('0','9');	//将0-9认作单词要素

但可能会遇到一个新的问题,如果我读取完纯数字字符串后,又想读取数字怎么办呢?(参考
PTA L1-005
这里提供两个思路,要么把空格也当作单词要素一起读进来用split解决,另一种就是我要讲的一种方法。

//先将数字当作字符进行读取
sc.ordinaryChars('0','9');
sc.wordChars('0','9');
sc.nextToken();
String s = sc.sval;
sc.parseNumbers();	//用这个方法可以把后面的数字都正常解析
sc.nextToken();
int testId = (int)sc.nval;
sc.nextToken();
int formalId = (int)sc.nval;

来点例子

前面也讲的差不多了,有蛮多方法虽然没讲到但是看字面还是蛮好理解的,而且目前写题也没怎么用到其他方法就是了,用到了再补。这里给两道题爽一爽。虽然说L1-005那道我还是没有全部AC

PTA L1-005,除了第二个测试点都能过

import java.io.*;
import java.util.*;

public class Main
{
    static StreamTokenizer sc =new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(System.out);

    public static void main(String[] args) throws IOException {
        sc.nextToken();
        int N = (int)sc.nval;
        String[] TestToId = new String[N + 1];
        int[] TestToFormal = new int[N + 1];
        for (int i = 0; i < N; i++) {
            sc.ordinaryChars('0','9');
            sc.wordChars('0','9');
            sc.nextToken();
            String s = sc.sval;
            sc.parseNumbers();
            sc.nextToken();
            int testId = (int)sc.nval;
            sc.nextToken();
            int formalId = (int)sc.nval;
            TestToId[testId] = s;
            TestToFormal[testId] = formalId;
        }
        sc.nextToken();
        int M = (int)sc.nval;
        int[] testM = new int[M];
        for (int i = 0; i < M; i++) {
            sc.nextToken();
            testM[i] = (int)sc.nval;
        }
        for (int id : testM) {
            out.printf("%s %s\n",TestToId[id],TestToFormal[id]);
        }
        out.flush();
        out.close();
    }
}

PTA L2-042,AC

import java.io.*;
import java.util.*;


public class Main
{
    static StreamTokenizer sc =new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(System.out);

    public static void main(String[] args) throws IOException
    {
        sc.nextToken();
        int n = (int)sc.nval;
        String l[] = new String[n + 10], r[] = new String[n + 10];
        sc.ordinaryChars('0','9');
        sc.wordChars('0','9');
        sc.wordChars(':',':');	//这里是因为分号也会被当作分隔符,加进去一起解析
        for (int i = 1; i <= n; i++)
        {
            sc.nextToken();
            l[i] =  sc.sval;
            sc.nextToken();
            String cache = sc.sval;
            sc.nextToken();
            r[i] =  sc.sval;
        }
        Arrays.sort(l, 1, n + 1);
        Arrays.sort(r, 1, n + 1);

        if (!l[1].equals("00:00:00"))
            out.println("00:00:00 - " + l[1]);

        for (int i = 2; i <= n; i++)
        {
            if (!r[i - 1].equals(l[i]))
                out.println(r[i - 1] + " - " + l[i]);
        }
        if (!r[n].equals("23:59:59"))
            out.printf(r[n] + " - 23:59:59");

        out.flush();
        out.close();
    }


}

BufferedReader类

如果只读整行的字符串其实这个就够用了,还省点事。但至于具体的时间对比就还没做。

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));	//初始化
String s = br.readLine();

自定义Reader类

这里是参考http://www.solohsu.com/blog/2014/04/07/faster-java-io-in-acm/制作的快速Scanner方法,对于L2-042的话能过四个测试点,还算ok

/** 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() );
      }
  }
posted @ 2023-04-21 14:17  Kitorio  阅读(246)  评论(0编辑  收藏  举报