您的位置:首页 > 编程语言 > Java开发

PAT乙级测试题及JAVA参考例程

2015-12-19 19:25 603 查看
PAT就是浙江大学程序设计能力考试,网址为http://www.patest.cn。考试分为乙级、甲级和Top。这里分享一下乙级测试题和我实现的一些解法,如果有不同的解法或者更好的实现方式,欢迎在文章下面回复。主要是在提交的时候,需要注意编译器里为Main.class 所以主类的命名要为Main。

刷到第11题以后,java的劣势体现出来了,题库的时间限制都是针对c的,java读入数据的时间就可能会超过时间限制,所以后来我就没有继续刷题了,现在在牛客网刷PAT和其他在线测试,后续还会在更新其他题目。

1001. 害死人不偿命的(3n+1)猜想 (15)

卡拉兹(Callatz)猜想:

对任何一个自然数n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把(3n+1)砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。卡拉兹在1950年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证(3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……

我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过1000的正整数n,简单地数一下,需要多少步(砍几下)才能得到n=1?

 

输入格式:每个测试输入包含1个测试用例,即给出自然数n的值。

 

输出格式:输出从n计算到1需要的步数。

 

输入样例:

3

输出样例:

5

这里第1题没有什么好说的,按照题目要求给出次数就好,代码如下。

import java.util.Scanner;

/**
*
* @author zjb
*/
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int num = Integer.parseInt(sc.nextLine());
int step=0;

while(num >1){
if(num%2 == 0){
num = num/2;
step++;
}
else{
num = (3*num+1)/2;
step++;
}
}
System.out.println(step);

}
}

1002. 写出这个数 (20)

读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字。

输入格式:每个测试输入包含1个测试用例,即给出自然数n的值。这里保证n小于10100。

 

输出格式:在一行内输出n的各位数字之和的每一位,拼音数字间有1 空格,但一行中最后一个拼音数字后没有空格。

 

输入样例:

1234567890987654321123456789

输出样例:

yi san wu

这个题一般也不会遇到什么问题,各个数位求和,然后求出和的每一位数,并且用switch语句和0到9的拼音匹配就好。代码如下:

import java.util.Scanner;
import java.util.Stack;

/**
*
* @author zjb
*/
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String numString = sc.next();

int num = 0;
int sum = 0;
for(int i=0; i<numString.length(); i++){
num = Integer.parseInt(numString.substring(i,i+1));
sum += num;
}
changenum(sum);
}
public static void changenum(int num){
//System.out.println(num);
Stack<Integer> stack = new Stack();
String output = new String();
String outtemp = new String();
int temp;
int flag = 0;
if(num ==0)
output += "ling";
while(num>0){
stack.push(num%10);
num = num/10;
}
while(!stack.empty()){
temp = stack.pop();
switch(temp){
case 0: outtemp = "ling";
break;
case 1: outtemp = "yi";
break;
case 2: outtemp = "er";
break;
case 3: outtemp = "san";
break;
case 4: outtemp = "si";
break;
case 5: outtemp = "wu";
break;
case 6: outtemp = "liu";
break;
case 7: outtemp = "qi";
break;
case 8: outtemp = "ba";
break;
case 9: outtemp = "jiu";
break;

}
if(flag ==0){
output += outtemp;
flag = 1;
}
else{
output =output+ " " +outtemp;
}
}
System.out.println(output);
}
}

1003. 我要通过!(20)

“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于PAT的“答案正确”大派送—— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。

得到“答案正确”的条件是:

 

1. 字符串中必须仅有P, A, T这三种字符,不可以包含其它字符;

2. 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;

3. 如果 aPbTc 是正确的,那么aPbATca 也是正确的,其中 a, b, c 均或者是空字符串,或者是仅由字母 A 组成的字符串。

 

现在就请你为PAT写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。

输入格式:每个测试输入包含1个测试用例。第1行给出一个自然数n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过100,且不包含空格。

 

输出格式:每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出YES,否则输出NO



 

输入样例:

 

8

PAT

PAAT

AAPATAA

AAPAATAAAA

xPATx

PT

Whatever

APAAATAA

输出样例:

YES

YES

YES

YES

NO

NO

NO

NO

这个题目会存在一些小小的问题,主要是对于题目的理解不是很到位引起的。

 

首先我们看题目的意思,1和2两点没有问题,主要是第3点,其实第3点是对第2点的推广。理解了这一点之后,就可以发现规律了。其实从2我们可以发现,在1 2的约束下,满足条件的只有两种形式PAT和APATA,那么3中满足条件的必然是从2推导出来的。

 

1.如果初始的是PAT那么接下来就是PAAT,再接下来就是PAAAT,以此类推。

 

2.如果初始状态是aPATa的话,那么接下来就是aPAATaa,在接下来就是aPAAATaaa,其中a为A的字符串,我们发现num(P前面a)*num(A)=num(T后面a),上面的形式也满足这个条件,所以我们可以利用这个约束来判断。下面是代码部分:

import java.util.Scanner;

/**
*
* @author zjb
*/
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
for
4000
(int i=0; i<num; i++){
int numa = 0;
int nump = 0;
int numt = 0;
boolean flag = false;
String str = sc.next();
for(int j=0; j<str.length(); j++){
char ch = str.charAt(j);

if(ch == 'A')
numa++;
else if(ch == 'P')
nump++;
else if(ch == 'T')
numt++;
else{
flag = false;
break;
}
}
if(numa>=1 && nump==1 && numt==1){
//System.out.println(str.indexOf('P'));
//System.out.println(str.indexOf('T'));
if(str.indexOf('P')*(str.indexOf('T')-str.indexOf('P')-1) == str.length() - str.indexOf('T')-1)
flag = true;
else
flag = false;
//str.indexOf('P')*(str.indexOf('T')-str.indexOf('P'));
//int numAbeforeP = str.indexOf('P');
}
if(flag)
System.out.println("YES");
else
System.out.println("NO");
}

}
}


1004. 成绩排名 (20)

读入n名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。

输入格式:每个测试输入包含1个测试用例,格式为

 

  第1行:正整数n

  第2行:第1个学生的姓名 学号 成绩

  第3行:第2个学生的姓名 学号 成绩

  ...... ...

  第n+1行:第n个学生的姓名 学号 成绩

其中姓名和学号均为不超过10个字符的字符串,成绩为0到100之间的一个整数,这里保证在一组测试用例中没有两个学生的成绩是相同的。

输出格式:对每个测试用例输出2行,第1行是成绩最高学生的姓名和学号,第2行是成绩最低学生的姓名和学号,字符串间有1空格。

 

输入样例:

3

Joe Math990112 89

Mike CS991301 100

Mary EE990830 95

输出样例:

Mike CS991301

Joe Math990112

这一题有几个注意点需要注意:

1.当n=1的时候需要处理,此时应该输出两行一样的姓名和学号

2. 由于提交的jdk版本是jdk1.6 不支持,自己实现Comparator接口,覆盖compare方法的sort,所以我这里使用了Collections.sort()进行排序,代码如下

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;

/**
*
* @author zjb
*/
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int rp = sc.nextInt();
String studentInfo = new String();
studentInfo = sc.nextLine();
List<String> studentList = new ArrayList();
List<Integer> studentscore = new ArrayList();
for(int i=0; i<rp; i++){
studentInfo = sc.nextLine();
studentList.add(studentInfo);
//System.out.println(studentInfo);
}
if(rp == 1){
String[] output = studentList.get(0).split(" ");
System.out.println(output[0]+" "+output[1]);
System.out.println(output[0]+" "+output[1]);
}
else{
for(int i=0; i<studentList.size(); i++){
String[] arr = studentList.get(i).split(" ");
studentscore.add(Integer.parseInt(arr[2]));
}
Collections.sort(studentscore);
Integer min = studentscore.get(0);
Integer max = studentscore.get(studentscore.size()-1);
String[] minString = new String[2];
String[] maxString = new String[2];
for(int i=0; i<studentList.size(); i++){
String[] arr = studentList.get(i).split(" ");
if(min.equals(Integer.parseInt(arr[2]))){
minString[0] = arr[0];
minString[1] = arr[1];
}
if(max.equals(Integer.parseInt(arr[2]))){
maxString[0] = arr[0];
maxString[1] = arr[1];
}

}
//String[] arr = maxString.split(" ");
System.out.println(maxString[0]+" "+maxString[1]);
//arr = minString.split(" ");
System.out.println(minString[0]+" "+minString[1]);

}

}

}

1005. 继续(3n+1)猜想 (25)

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。

当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对n=3进行验证的时候,我们需要计算3、5、8、4、2、1,则当我们对n=5、8、4、2进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这4个数已经在验证3的时候遇到过了,我们称5、8、4、2是被3“覆盖”的数。我们称一个数列中的某个数n为“关键数”,如果n不能被数列中的其他数字所覆盖。

现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

 

输入格式:每个测试输入包含1个测试用例,第1行给出一个正整数K(<100),第2行给出K个互不相同的待验证的正整数n(1<n<=100)的值,数字间用空格隔开。

 

输出格式:每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用1个空格隔开,但一行中最后一个数字后没有空格。

 

输入样例:

6

3 5 6 7 8 11

输出样例:

7 6

这个题就是1001的延续,这里对每一个输入的数字,都遍历一边整个输入的验证过程,这种方式比较消耗内存,可以看到我在这里使用了3个ArrayList,

还有一种方法就是对每一个输入做一次卡拉茨验证,然后设立一个标记数组,由于输入不超过1000,所以可以设置标记数组flag[3001],在循环验证输入的时候,比如验证了2那么就对flag[2]++,这样只要进行一次遍历验证,那么就可以得到flag,查找flag中大于1的项就是重复验证的项,这样就只需要开销一个list和一个数组,这种方法在输入比较多的时候比较快速。

三个List的代码如下:

import java.util.*;
/**
*
* @author zjb
*/
public class Main {

public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int rp = sc.nextInt();
int numin;
int num;
List<Integer> list = new ArrayList();
List<Integer> copylist = new ArrayList();
List<Integer> specillist = new ArrayList();
for(int i=0; i<rp; i++){
numin = sc.nextInt();
list.add(numin);
copylist.add(numin);
}
//copylist = list;
Iterator it = list.iterator();

while(it.hasNext()){
num = (Integer)it.next();
//  System.out.println(num+"++");
if(!ifSpecil(copylist,num)){
specillist.add(num);
// System.out.println(num);
}
}
// B1005CMP cmp =  new B1005CMP();
Collections.sort(specillist);
for(int i=specillist.size()-1; i>=0; i--){
if(i == specillist.size()-1)
System.out.print(specillist.get(i));
else
System.out.print(" "+specillist.get(i));
}
}
public static boolean ifSpecil(List copylist, int num){
boolean flag = false;
Integer testnum;
for(int i=0; i<copylist.size(); i++){
testnum = (Integer)copylist.get(i);
//System.out.println(testnum);
while(testnum>1&&!(testnum.equals(num))){
if(testnum%2 == 0){
testnum = testnum/2;
if(testnum == num)
flag = true;
}
else{
testnum = (3*testnum+1)/2;
if(testnum == num){
flag = true;

}
}
}
}
return flag;
}
}

1006. 换个格式输出整数 (15)

让我们用字母B来表示“百”、字母S表示“十”,用“12...n”来表示个位数字n(<10),换个格式来输出任一个不超过3位的正整数。例如234应该被输出为BBSSS1234,因为它有2个“百”、3个“十”、以及个位的4。

 

输入格式:每个测试输入包含1个测试用例,给出正整数n(<1000)。

 

输出格式:每个测试用例的输出占一行,用规定的格式输出n。

 

输入样例1:

234

输出样例1:

BBSSS1234

输入样例2:

23

输出样例2:

SS123

这道题比较简单,代码如下

import java.util.*;
/**
*
* @author zjb
*/
public class Main {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
int numb = num/100;
num = num%100;
int nums = num/10;
int numg = num%10;
String output = new String();
while(numb > 0){
output += "B";
numb--;
}
while(nums > 0){
output += "S";
nums--;
}
for(int i=1; i<numg+1; i++){
output += i;
}
System.out.println(output);

}
}


1007. 素数对猜想 (20)

让我们定义 dn 为:dn = pn+1 - pn,其中 pi 是第i个素数。显然有 d1=1 且对于n>1有 dn 是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。

现给定任意正整数N (< 105),请计算不超过N的满足猜想的素数对的个数。

 

输入格式:每个测试输入包含1个测试用例,给出正整数N。

 

输出格式:每个测试用例的输出占一行,不超过N的满足猜想的素数对的个数。

 

输入样例:

20

输出样例:

4

这个题目需要注意的是

1.不超过N的素数对,那么对于N是偶数和基数就要分开处理了

2.判断素数的时候for(int i=2;i<Math.sqrt(num)+1; i++)只要整除num的开放加1就可以判断是不是素数,如果从2到nun-1的话,很可能超时间。

代码如下:

import java.util.*;
/**
*
* @author zjb
*/
public class Main {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
int pairnum = 0;
int up = (num%2 == 1)? num/2:num/2-1;
for(int i=1; i<=up; i++){
if(isPrime(2*i-1)&&isPrime(2*i+1))
pairnum++;
}
System.out.println(pairnum);
}
public static boolean isPrime(int num){
if(num <= 2)
return false;
for(int i=2; i<Math.sqrt(num)+1; i++){
if(num%i == 0)
return false;
}
return true;
}
}

1008. 数组元素循环右移问题 (20)

一个数组A中存有N(N>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0A1……AN-1)变换为(AN-M …… AN-1 A0 A1……AN-M-1)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

 

输入格式:每个输入包含一个测试用例,第1行输入N ( 1<=N<=100)、M(M>=0);第2行输入N个整数,之间用空格分隔。

 

输出格式:在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。

 

输入样例:

6 2

1 2 3 4 5 6

输出样例:

5 6 1 2 3 4

这个题目说是不允许使用另外数组的前提下,当然如果使用另外的数组当然可以通过提交,因为测试用例测试不出来你是否使用了另外的数组,当然作为练习阶段当然还是不适用另外的数组比较好,其实实现起来也比较容易,因为N<=100,所以只要声明一个200的数组就,就可以把数组先整体后移动,再把后面的移上来就好了。代码如下所示:

import java.util.*;
/**
*
* @author zjb
*/
public class Main {
private int[] a;
private int N;
private int M;

public Main(int[]a, int N, int M){
this.a = a;
this.N = N;
this.M = M;
}
public  void cycleMove(){
for(int i=N-1; i>=0; i--){
a[i+M] = a[i];
}
for(int i=0; i<M; i++){
a[i] = a[N+i];
}
}

public  void display(){
for(int i=0; i<N; i++){
// System.out.println("+++++++++");
if(i == 0)
System.out.print(a[i]);
else
System.out.print(" "+a[i]);
}
}
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
M = M%N;
int[] a =  new int[200];
for(int i=0; i<N; i++){
a[i] = sc.nextInt();
}
// System.out.println("+++++++++");
Main my = new Main(a,N,M);
// my.display();
my.cycleMove();
my.display();
}
}

1009. 说反话 (20)

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

 

输入格式:测试输入包含一个测试用例,在一行内给出总长度不超过80的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用1个空格分开,输入保证句子末尾没有多余的空格。

 

输出格式:每个测试用例的输出占一行,输出倒序后的句子。

 

输入样例:

Hello World Here I Come

输出样例:

Come I Here World Hello

这个题目很简单没什么好说的,实现方法也很多,代码如下:

import java.util.*;
/**
*
* @author zjb
*/
public class Main {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String[] strarr = str.split(" ");
for(int i=strarr.length-1; i>=0; i--){
if(i==strarr.length-1)
System.out.print(strarr[i]);
else
System.out.print(" "+strarr[i]);
}
}
}

1010. 一元多项式求导 (25)

设计函数求一元多项式的导数。(注:xn(n为整数)的一阶导数为n*xn-1。)

 

输入格式:以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。

 

输出格式:以与输入相同的格式输出导数多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。注意“零多项式”的指数和系数都是0,但是表示为“0 0”。

 

输入样例:

3 4 -5 2 6 1 -2 0

输出样例:

12 3 -10 1 6 0

这个题目很奇怪,因为其实题目已经给你规定好输入格式了非零项的系数和指数。如果n为
af7d
洗漱,e为指数的话,保证了a大于0,只要考虑e大于零输出就好了,很奇怪的时候最后输入"0 0"的语句,理论上是永远达不到的,可能测试样对于0多项式的测试,采用了终止Scanner的方式,这样必须在后面加个判断,这个也是我网上找的处理方式,其实一开始我自己写的也一直过不了测试点,代码如下:

import java.util.*;
/**
*
* @author zjb
*/
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int a,b;
boolean flag = false;
while(sc.hasNext()){
a = sc.nextInt();
b = sc.nextInt();
if(b>0)
if(!flag){
System.out.print(a*b+" "+(b-1));
flag = true;
}
else{
System.out.print(" "+a*b+" "+(b-1));
}

}
if(!flag)
System.out.print("0 0");
}
}

1011. A+B和C (15)

给定区间[-231, 231]内的3个整数A、B和C,请判断A+B是否大于C。

输入格式:

 

输入第1行给出正整数T(<=10),是测试用例的个数。随后给出T组测试用例,每组占一行,顺序给出A、B和C。整数间以空格分隔。

 

输出格式:

 

对每组测试用例,在一行中输出“Case #X: true”如果A+B>C,否则输出“Case #X: false”,其中X是测试用例的编号(从1开始)。

 

输入样例:

4

1 2 3

2 3 4

2147483647 0 2147483646

0 -2147483648 -2147483647

输出样例:

Case #1: false

Case #2: true

Case #3: true

Case #4: false

这个题目需要注意的是int类型的长度,java中int为32位所以会存在越界的现象,换成Long类型就没有问题了,代码如下:

import java.util.*;
/**
*
* @author zjb
*/
public class Main {
public static void main(String[] args){
//System.out.print(Integer.SIZE);
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
sc.nextLine();
List<String> list = new ArrayList();
for(int i=0; i<T; i++){
list.add(sc.nextLine());
}
for(int i=0; i<T; i++){
String[] strarr = list.get(i).split(" ");
long A = Long.parseLong(strarr[0]);
long B = Long.parseLong(strarr[1]);
long C = Long.parseLong(strarr[2]);
//System.out.print(A+" "+B+" "+C+" ");
if(A+B > C)
System.out.println("Case #"+(i+1)+": true");
else
System.out.println("Case #"+(i+1)+": false");
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息