PAT甲级 1001 A+B Format 20分

题目简介

Calculate a+b and output the sum in standard format – that is, the digits must be separated into groups of three by commas (unless there are less than four digits).

输入信息

Each input file contains one test case. Each case contains a pair of integers a and b where ​​ -10^6 <= a,b <= 10^6 The numbers are separated by a space.

输出信息

For each test case, you should output the sum of a and b in one line. The sum must be written in the standard format.

输入样例

-1000000 9

输出样例

-999,991

分析

给定两个数a和b,计算他们的和,并每三个添加分隔符(在千分位添加分隔符)
由于都是在int范围内,所以不用考虑溢出的问题。(最大2×10^6)

首先有一个最简单的方法,就是掏出Java里面一个非常有用的类——DecimalFormat
(PS:在PAT考试里面,对于时间限制要求不高的20分题目,用Java往往可以很快秒杀。只要用好String、BigInteger、DecimalFormat等类)

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.StringTokenizer;

public class Main {
	static final int BUFFER_SIZE = 8192 * 25;
	static BufferedReader br;
	static StringTokenizer tokenizer;

	static void initInput(InputStream in) throws Exception {
		br = new BufferedReader(new InputStreamReader(in), BUFFER_SIZE);
		tokenizer = new StringTokenizer("");
	}

	static String next() throws Exception {
		while (!tokenizer.hasMoreTokens()) {
			tokenizer = new StringTokenizer(br.readLine());
		}
		return tokenizer.nextToken();
	}

	static int nextInt() throws Exception {
		return Integer.parseInt(next());
	}

	static PrintWriter pw;

	public static void main(String[] args) throws Exception {
		initInput(System.in);
		pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out), BUFFER_SIZE));
		
		/*正式代码开始*/
		int a = nextInt(),b=nextInt();
		int c = a+b;
		DecimalFormat df = new DecimalFormat("#,###");
		//如果要求按四位分割,就改为#,####即可
		pw.println(df.format(c));
		/*结束*/
		
		pw.flush();
	}
}

如图,核心代码只有四行。(关于为什么IO要这么写的说明附在文后,并会给出一个模版)
PAT甲级 1001 A+B Format 20分_第1张图片
不出意料,耗时和内存都很高,这是用Java写PAT的常态(Python耗时都比Java强。但是不妨碍好用~过了就行)

正常考试我们1分钟拿到分就跑了,但是作为学习阶段应该再认真思考一下到底应该怎么做。
对于一个数 1234567890 (求和之后),应该表示为1,234,567,890
如果将这个数转化为字符串,其每一位的字符与下标对应关系如下:
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 0
可以看出,在打印str[0] 、str[3]、str[6]字符之后需要打印一个逗号。
通过观察规律,设下标为i,则满足条件 (i+1)%3==len%3 时需要打印一个逗号。如果 i 是最后一位(即 i==len-1 )不需要打印。如果是负数,跳过即可,同样符合这个规律。
如: -1234567
0 1 2 3 4 5 6 7

  • 1,2 3 4,5 6 7
    在str[1],str[4]之后打印逗号。
    (参考 @柳婼 的思路)
    C++实现如下:
#include 
#include 
using namespace std;
int main() {
	int a, b;
	scanf("%d %d", &a, &b);
	string s = to_string(a + b);
	for (int i = 0; i < s.length(); i++) {
		printf("%c", s[i]);
		if (s[i] != '-' && (i + 1) % 3 == s.length() % 3 && i != s.length() - 1)
			printf(",");
	}
	return 0;
}

PAT甲级 1001 A+B Format 20分_第2张图片
(这个耗时就是天差地别了。。。)

附录-关于PAT考试中效率(运行时间的问题)

刚开始的三四十道题我也是采用Java答题,但是后面部分题目实在是无法通过。(限时300ms以下的题目,用Java通过几乎 不可能),下面对于Java的技巧,也仅仅是在一定程度上改良,如果只是自己学着练练题目,可以用Java写,但是如果是要参加考试,请趁早转行。原因在于:
1、Pat官方解释,呵呵,就这样。
2、PTA的判题系统里Java相关的编译程序已经许久 没有维护,Java虚拟机的启动时间也被算在程序运行时间内。
一、如果采用Java答题
Java属于先编译后解释的语言,虽然由.java编译成.class文件的时间不算在内,但是Java虚拟机启动(长达50ms+)的时间会被算在里面。如果采用了低效的IO方法,效果会更差。相比而言,纯解释型语言(如Python),反倒更快(相比较而言)。
下面的几个提升运行速度的方法,实际效果依次减弱。

  • 使用C++改写。
  • 停止使用Scanner读入,改用封装过的Reader类
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)));

Scanner虽然方便好用,但是效率极差,参见
Fast Input for Java
某使用Java打国际acm选手做的实验

  • 使用StringTokenizer代替String.parse,StringTokenizer的效率会比String.parse高好几倍。
  • 在上一条中的链接里也有解释。
  • 停止使用System.in输出,改用封装过的Writer类。
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));

使用BufferedWriter封装转化而来的System.out,可以提高效率,再使用PrintWriter封装,可以方便使用print、printf、println等方法。

  • 所有可以静态化的对象尽量静态化(存疑)
    这个做法的由来是GC不会检查并回收在静态域中的对象,而减少GC的频率则能一定程度提高运行效率(实际上效果非常不明显, 几乎没有)
    将不用的对象及时置为null也或许能提高一点效率
  • 修改BufferedReader、BufferedWriter默认的缓冲区大小(默认值为8192,我将它增大到原来的25倍),以内存换读取效率。
    这也是为什么要写一行:
static final int BUFFER_SIZE = 8192 * 25;

忘了是在哪里见过一次别人这么写,实际 效果存疑, 可能并无卵用。

综上几条可以得出Java里面最高效的读写模版如下:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main{
	static final int BUFFER_SIZE = 8192*25;
	static BufferedReader br;
	static StringTokenizer tokenizer;

	static void initInput(InputStream in) throws Exception {
		br = new BufferedReader(new InputStreamReader(in), BUFFER_SIZE);
		tokenizer = new StringTokenizer("");
	}
	static String next() throws Exception{
		while(!tokenizer.hasMoreTokens()) {
			tokenizer = new StringTokenizer(br.readLine());
		}
		return tokenizer.nextToken();
	}

	static int nextInt() throws Exception {
		return Integer.parseInt(next());
	}
	static double nextDouble() throws Exception{
		return Double.parseDouble(next());
	}
	static PrintWriter pw;
	public static void main(String[] args) throws Exception {
		initInput(System.in);
		pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out),BUFFER_SIZE));
		
		/*在这里插入你的代码*/
		int i = nextInt(); //读取一个整数
		String s = next(); //读取一个字符串
		double d = nextDouble(); //读取一个浮点数
		pw.flush();
	}
}

注:StringTokenizer的默认分隔符是空格和换行,如果需要其他方式,还是用next()读取字符串后使用spilt方法比较合适。
二、如果采用C语言答题
改用C++,没有STL基本上不能活。
三、如果采用C++答题
C++没什么好说的,一般来说没有大问题(很多时候 ,Java需要采用最优化的算法才能过,C++甚至暴力就行了)
只有几点需要注意:

  • 尽量采用scanf和printf来读取或输入(有人说cin、cout取消刷新也可),特别是在需要读取大量字符串的时候,scanf的效率提升尤为明显。
  • 善用map、set、unordered_map和unordered_set。一般来说,如果key是int类型都可以用数组代替,key是string类型时候才用map。但是如果数据量超大,就要用到unordered_map。(map/set底层是红黑树实现,能保证一定有序性,unordered_map/unordered_set底层是哈希表实现,效率稍高,但建表需要时间)
    结论是:
    一般情况下用数组,只需要key不需要value用set/unordered_set
    key为string时用map。
    数据量大(用map超时),不需要有序性时使用unordered_map。使用unordered_map时,尽量在初始化时就指定好大小(减少哈希表扩容带来的开销)
    需要有序性(排序)时,使用map。(后面题目会见到)
  • 一些小的点,能用邻接表就不用邻接矩阵,用stringstream拼接字符串而不是重载的运算符等等
  • 使用vector代替普通数组。数组能干的vector都能,而且更方便。

当然了,有的时候图方便可以采用一点低效的方法。反正错了还可以再改(PAT考试不罚时)(逃)

你可能感兴趣的:(PAT甲级,算法,java,c++)