PTA平台 · PAT(Basic Level) Practice(中文) 题目集
本文是PTA平台上收录的PAT乙级真题的参考代码(我自己写的),共115道题,主要用Java语言完成。
前 言
※ PTA是 程序设计类实验辅助教学平台 ,里边包含一些编程题目集以供练习。
※ PAT是 浙江大学计算机程序设计能力考试(Programming Ability Test),分为乙级(中文、基础编程)、甲级(英文、基础数据结构)、顶级(国际竞赛水平)。
※ 本文是PTA平台上收录的PAT乙级真题的参考代码(我自己写的),共115道题,主要用Java语言完成。
目 录
1001 害死人不偿命的(3n+1)猜想
题目
作者 CHEN, Yue
单位 浙江大学
卡拉兹(Callatz)猜想:
对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把 (3n+1) 砍掉一半。这样一直反复砍下去,最后一定在某一步得到 n=1。卡拉兹在 1950 年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证 (3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……
我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过 1000 的正整数 n,简单地数一下,需要多少步(砍几下)才能得到 n=1?
输入格式:
每个测试输入包含 1 个测试用例,即给出正整数 n 的值。
输出格式:
输出从 n 计算到 1 需要的步数。
代码
import java.io.* ; //功能:给定一个正整数,计算验证卡拉兹猜想需要砍半的次数
class Main{ // 空间复杂度O(1)
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int k = Integer.parseInt(br.readLine());
//计算
int i = 0; //计数器,所需要的步数
for(i = 0;k != 1;i++)
if(k%2 == 0) //若k为偶数,就砍一半
k = k/2;
else
k = (3*k+1)/2; //若k为奇数,就将(3n+1)砍一半
//打印
System.out.println(i);
}
}
1002 写出这个数
题目
作者 CHEN, Yue
单位 浙江大学
读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字。
输入格式:
每个测试输入包含 1 个测试用例,即给出自然数 n 的值。这里保证 n 小于 10^100。
输出格式:
在一行内输出 n 的各位数字之和的每一位,拼音数字间有 1 空格,但一行中最后一个拼音数字后没有空格。
输入样例:
1234567890987654321123456789
输出样例:
yi san wu
代码
import java.io.*; //功能:用汉语拼音写出一个数字的个位数字之和
class Main{ //时间复杂度O(n) 空间复杂度O(n) n为数字大小(给定字符串长度)
public static void main(String[] args) throws IOException{
//获取输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();
//计算各位数字之和
int sum = getSum(str);
//获取对应的拼音
String s = getStr(sum);
//打印
System.out.println(s.trim()); //String.trim()去除字符串首尾空格
}
//获取给定字符串的各位数字之和 //时间复杂度O(n) 空间复杂度O(1) n为字符串长度
private static int getSum(String s){
int t = 0;//各位数字之和
String c = "";//当前取出的一个数字的字符串
for (int i = 0; i<s.length();i++){ //遍历字符串的每个字符
c = s.substring(i,i+1);
t = t + Integer.parseInt(c); //求和
}
return t;
}
//获取给定int的每一位的数字拼音字符串 //时间复杂度O(n) 空间复杂度O(n) n为数字大小
private static String getStr(int n){
String[] arr = "ling yi er san si wu liu qi ba jiu".split(" "); //以数组形式建立数字-拼音对照表
String str = n + ""; //将给定int转为字符串
String goal = ""; //最终打印输出的目标字符串
int a = 0; //数字-拼音对照表的索引,也就是数组的角标
for(int i = 0;i<str.length();i++){ //遍历字符串中每一个数字字符
a = Integer.parseInt(str.substring(i,i+1)); //将当前字符转为数字,赋值给a
goal = goal + arr[a] + " "; //以a作为角标,在对照表中找到对应拼音,添加进目标字符串中
}
return goal; //这里返回的目标字符串,尾部带有一个多余的空格。
}
}
1003 我要通过!
题目
作者 CHEN, Yue
单位 浙江大学
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
- 字符串中必须仅有
P
、A
、T
这三种字符,不可以包含其它字符; - 任意形如
xPATx
的字符串都可以获得“答案正确”,其中x
或者是空字符串,或者是仅由字母A
组成的字符串; - 如果
aPbTc
是正确的,那么aPbATca
也是正确的,其中a
、b
、c
均或者是空字符串,或者是仅由字母A
组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (≤10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过 100,且不包含空格。
输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES
,否则输出 NO
。
输入样例:
10
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT
APATTAA
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
NO
NO
分析
首先要分析判定规则。
1.根据第一条规则,字符串中只能有PAT这三个字符,否则判定为NO。
2.根据第二条规则,形如 xPATx 的判定为YES,而x表示0个或多个字符A。由此可知,正确的字符串应该是,P之前可以有字符A(假设数量为a),P与T之间可以有字符A(假设数量为b),T之后可以有字符A(假设数量为c)。字符P和T是必须有且仅能有一个的,而且前后顺序是固定的。至于abc的值有什么具体要求,就要进一步分析了。题目的第二条规则说明,当b=1且a=c时,判定为YES。这可以看做是基础版的规则。
这个基础版的规则,也可以理解为,① c=a=0 , b=1 ② c=a>0 ,b=1 (也可以看做是 c / a = b=1)这两种情况都判定为YES。
3.根据第三条规则,b也可以>1,并且在第二条规则的基础上,每当b = b+1时,c=c+a,也就是说,c / a = b (当a≠0时) 。那么现在也有两种情况可以判定为YES,① c=a=0 , b≥1 ,② a≠0, c / a = b ≥ 1 。这就是判定逻辑。总结一下就是,要求b > 0;且要求 要么c=a=0 ,要么 c / a=b 。
代码
import java.io.*; //功能:根据给定规则,判断一组字符串是否正确并打印结果
class Main{ //时间复杂度O(n) 空间复杂度 O(n) n为字符串个数
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
byte n = Byte.parseByte(br.readLine()); //读取待检查的字符串个数
//处理数据
String s =""; //辅助字符串,用于接收当前待检查字符串
String[] arr = new String[n]; //存放对每个字符串的检测结果,YES 或 NO
for (int i = 1;i<=n;i++){
s = br.readLine(); //依次从函数外部读取待检查的字符串
arr[i-1] = getAns(s); //计算该串是否通过的检测结果,并存入数组中
}
//打印输出
for (int i = 0;i<n;i++) //遍历检测结果数组,输出检测结果
System.out.println(arr[i]);
}
//给定一个字符串,返回判定结果字符串
private static String getAns(String str){ //时间复杂度O(n) 空间复杂度O(1) n为字符串长度
String s = ""; //辅助字符串
byte a = 0,b = 0, c = 0; //a表示P前边有几个A //b表示PT之间有几个A,要求b > 0 //c表示T之后有几个A,要求 要么c=a=0,要么c/a=b
byte flag = 1; //用于标记当前对字符串读取到哪个阶段,初始化标记为第一阶段
exam: for(int i = 0;i<str.length();i++){ //逐个读取字符,分阶段计算abc的值
s = str.substring(i,i+1); //读取当前的一个字符
switch(flag){
case 1: //阶段1 计算a的值
if (s.equals("A")) //每读取到一个A,则a+1
a++;
else if(s.equals("P")) //若读取到的字符是P,说明第一阶段结束
flag = 2;
else //若读取到的是其它字符,则不符合规则,直接退出for语句的判断
break exam ;
break;
case 2: //阶段2 计算b的值
if(s.equals("A")) //每读取到一个A,则b+1
b++;
else if(s.equals("T") && b > 0 ) //若读取到的字符是T,说明第二阶段结束
flag = 3; //若符合b>0的要求,则进入下一阶段
else //若不满足b>0的要求,或者读取到的是其它字符,则不符合规则,直接退出for语句的判断
break exam ;
break;
case 3: //阶段3 计算c的值
if(s.equals("A")) //每读取到一个A,则c+1
c++;
else //若读取到的是其它字符,则不符合规则,直接退出for语句的判断
break exam ;
break;
default: //应对意外情况
System.out.println("flag表示有误!");
} //switch语句
} //for语句
if(flag == 3) //依据规则要求判断字符串是否合格
if(c == a && a == 0) //符合规则的情况1:c=a=0,b>0
return "YES";
else if(c / a == b) //符合规则的情况2:c/a=b>0
return "YES";
return "NO"; //若没有完成三个阶段的计数,或者完成了但是最终结果不合格,则判定结果都是NO
} //getAns函数
} //class Main
1004 成绩排名
题目
作者 CHEN, Yue
单位 浙江大学
读入 n(>0)名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。
输入格式:
每个测试输入包含 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
代码
import java.io.*; //功能:给定一组学生姓名、学号、成绩,输出最高分与最低分学生信息
class Main{ //时间复杂度O(n) 空间复杂度O(n) n为学生个数
public static void main(String[] args) throws IOException{
//获取输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());//读取学生个数
//读取第一个学生的信息 题目给定n>0,因此一定能读取到至少一个学生的信息
String[] arra = new String[3]; //存储最高分学生的信息
String[] arrb = new String[3]; //存储最低分学生的信息
String[] arrc = new String[3]; //存储当前读取的学生信息
String s = "";
arra = br.readLine().split(" "); //读取第一个学生的信息
arrb = arra; //复制学生信息
//在线处理 在线处理是指,从第二个学生开始,每读取一条信息就立即更新最高分和最低分记录
for(int i=2;i<=n;i++){
arrc = br.readLine().split(" "); //读取当前学生的信息
if(Integer.parseInt(arrc[2]) > Integer.parseInt(arra[2])) //判断是否需要更新最高分记录
arra = arrc;
else if(Integer.parseInt(arrc[2]) < Integer.parseInt(arrb[2])) //判断是否需要更新最低分记录
arrb = arrc;
else //无需更新记录的话,就继续读取下一条
continue;
}
//打印输出
System.out.println(arra[0] + " " + arra[1]); //打印最高分学生信息
System.out.println(arrb[0] + " " + arrb[1]); //打印最低分学生信息
}
}
1005 继续(3n+1)猜想
题目
作者 CHEN, Yue
单位 浙江大学
卡拉兹(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
代码
import java.io.*; //功能:给定一组数字,找出在验证卡拉兹猜想过程中的关键数,并降序输出
import java.util.*; //空间复杂度O(n)
class Main{
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine().trim();
int n = Integer.parseInt(s); //读取待验证的数字个数
//数组初始化
String[] arrStr = br.readLine().split(" +"); //读取待验证数字(String)
int[] arr = new int[n]; //arr数组存储所有待验证的n个正整数(int)
for(int i=0;i<n;i++)
arr[i] = Integer.parseInt(arrStr[i]);
//遍历arr数组,逐个数字验证3n+1猜想
/*思路:arr[]初始存储的是所有待验证的正整数,如果某个正整数被覆盖,就把数值标记为-1 */
int t; //辅助
for(int i=0;i<n;i++){
t=arr[i]; //从数组中读取当前数字
if(t<0) //如果当前数字已被覆盖,就不用再验证了
continue;
while(t>1){ //如果当前数字没有被覆盖,那就验证3n+1猜想,直到结果=1
if(t%2==0) //若为偶数,则直接砍半
t = t/2;
else //若为奇数,则将(3n+1)砍半
t = (3 * t + 1)/2;
for(int j=0;j<n;j++) //检查运算结果是否覆盖了数组中的数字
if(arr[j]>0 && arr[j]==t){ //如果数组中有某个数字未被覆盖且与当前数字相等
arr[j]=-1; //则将它置为-1,标记为覆盖
break; //数组中其它数字不用看了,因为是互不相等的
}
} //while
}//for
//将关键字降序输出
Arrays.sort(arr); //将数组升序排序
String str = "";
for(int i=n-1;i>=0;i--) //生成待打印的字符串 值为-1的就是被覆盖的,就不打印
if(arr[i]>0)
str = str + arr[i] + " ";
else
break;
System.out.println(str.trim()); //打印输出 去除字符串首尾空格
} //main函数
} //class Main
1006 换个格式输出整数
题目
作者 CHEN, Yue
单位 浙江大学
让我们用字母 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.io.*; //功能:给定一个正整数,按指定规则重新输出这个数
class Main{ //时间复杂度O(n) 空间复杂度O(n) n为数值大小(给定字符串长度)
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int bai = n / 100; //获取百位数
int shi = n % 100 /10; //获取十位数
int ge = n % 10; //获取个位数
//打印
String s = "";
for (int i = 1;i<=bai;i++) //打印百位数
s = s + "B";
for (int i = 1;i<=shi;i++) //打印十位数
s = s + "S";
for (int i = 1;i<=ge;i++) //打印个位数
s = s + i;
System.out.println(s);
}
}
1007 素数对猜想
题目
作者 CHEN, Yue
单位 浙江大学
让我们定义dn为:dn=pn+1−pn,其中pi是第i个素数。显然有d1=1,且对于n>1有dn是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。
现给定任意正整数N
(<105),请计算不超过N
的满足猜想的素数对的个数。
输入格式:
输入在一行给出正整数N
。
输出格式:
在一行中输出不超过N
的满足猜想的素数对的个数。
输入样例:
20
输出样例:
4
代码
import java.io.*; //给定正整数n,计算不超过n的素数对的数量
class Main{ // 时间复杂度O(n√n) 空间复杂度O(n) n为给定正整数的大小
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine()); //正整数n
//处理特殊值
if(n < 5){ //若给定数字<5,则满足猜想的素数对为0,打印结果后返回
System.out.println(0);
return;
}
//计算素数对的数量 //***思路:对于≥6的整数,素数只有可能出现在6n-1或6n+1的位置,n为正整数。
int t = 1; //计数器,素数对个数(初始值为1是预加上3 5 这一对)
for(int i = 1;6*i+1<=n;i++) //遍历n,计算素数对的数量
if(ifsushu(6*i-1) && ifsushu(6*i+1) )
t++;
System.out.println(t); //打印输出
}
//判断一个整数是否是素数 时间复杂度为O(√n) 空间复杂度O(1) n为数值t的大小
private static boolean ifsushu(int t){
//判断特殊值
if(t==2 || t==3 || t==5) return true;
//若尾数不是1 3 7 9 则一定不是素数(6以上的数)
if(t%2==0 || t%5==0) return false;
//若此数不是6n+1或者6n-1,则一定不是素数(6以上的数)
if((t+1)%6!=0 && (t-1)%6!=0) return false;
//遍历检查(合数一定能分解为质数的乘积)
for(int i=1;Math.pow(6*i-1,2)<=t;i++)
if(t % (6*i-1) == 0 || t % (6*i+1) == 0)
return false;
return true;
}
}
1008 数组元素循环右移问题
题目
作者 DS课程组
单位 浙江大学
一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A0A1⋯AN−1)变换为(AN−M⋯AN−1A0A1⋯AN−M−1)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?
输入格式:
每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(≥0);第2行输入N个整数,之间用空格分隔。
输出格式:
在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。
输入样例:
6 2
1 2 3 4 5 6
输出样例:
5 6 1 2 3 4
代码 - C语言
这道题与2010年考研408真题42题很像,只不过将左移改为了右移。这道题我在 《【考研·数据结构】408真题 (2010年42题) 的三种解法》 这篇博客中单独写了代码实现思路。因为原先做过这道真题,于是在这里我就在录入数据后简单处理,将右移的元素个数转换为左移的元素个数,这样原来的实现代码不变。
408真题的参考答案中给出了两种解法(原地逆置法、辅助数组法),我自己写了第三种解法(循环填空法)。因为是考研真题(要求用C语言),我就用C语言实现了。不过PTA平台上的这道题,要求不能使用额外的数组,因此解法2不适用,就当做一种思路的拓展吧。
#include <stdio.h> //C语言
void myprint001(int R[],int n);
void Converse(int R[],int n,int p);
void Reverse(int R[],int from,int to);
void Converse2(int R[],int n,int p);
void myMove(int R[],int n,int p);
int main() { //功能:将数组元素循环右移p个元素
//这与2010年考研408的42题很像,只不过把向左移动改为了向右移动。
//共有三种解法,时空复杂度在每个解法中单独分析
//录入数组数据
int n,p,t,a;
scanf("%d %d",&n,&p);
if(p%n==0) p = 0; //这句不能整合在下一个if语句中
if(p>0) p = n - (p%n); //本来接收的数据p表示要右移的元素个数,经过这一步处理后,转变为要左移的元素个数
int R[n];
for(int i=0;i<n-1;i++){
a=scanf("%d ",&t);
R[i] = t;
}
a=scanf("%d",&t);
R[n-1] = t;
//myprint001(R,n); //打印初始数组
//解法1:原地逆置法
Converse(R,n,p);
//解法2:辅助数组法
//Converse2(R,n,p);
//解法3:循环填空法
//myMove(R,n,p);
myprint001(R,n); //打印移位后的数组
return 0;
}
//解法1
void Converse(int R[],int n,int p){
/*功能:将数组R的元素循环左移p个位次*/
/*实现思路:
利用三次原地逆置实现。
根据p的位置将数组看做ab两部分,
第一次逆置a,数组变为(-a)b,
第二次逆置b,数组变为(-a)(-b)
第三次逆置整个数组,数组变为ba。*/
/*时间复杂度:O(n);空间复杂度:O(1) */
Reverse(R,0,p-1);
Reverse(R,p,n-1);
Reverse(R,0,n-1);
}
void Reverse(int R[],int from,int to){
/*功能:将数组R中指定角标范围内的部分原地逆置*/
int i,temp; //i是计数器,temp用于暂存元素以便于逆置交换
for(i=0;i<(to-from+1)/2;i++){
temp = R[from+i];
R[from+i] = R[to-i];
R[to-i] = temp;
}
}
//解法2
void Converse2(int R[],int n,int p){
/*实现思路:
利用一个辅助数组S,暂存前p个元素,之后将后面的元素移位,
再将前p个元素移位到正确位置。
*/
/*时间复杂度:O(n) ;空间复杂度: O(p) */
int S[p]; //创建一个辅助数组
for(int i=0;i<=p-1;i++) //将R中前p个元素移到S中
S[i] = R[i];
for(int i=p;i<n;i++) //将R中p及后面的元素移到正确位置
R[i-p] = R[i];
for(int i=0;i<=p-1;i++) //将S中的元素移到R中正确位置
R[n-p+i] = S[i];
}
//解法3
void myMove(int R[],int n,int p){
/* 接收的参数:
R[] 要重新排序的数组;n 数组R中元素的个数 ;p 要向左移动几位 */
/*功能:
将含有n个元素的int数组R中的元素循环左移p位 */
/*实现思路:
1.将首元素暂存于x,则首元素的位置视为空,接下来逐个移位填空。
移位时,R[i]为目前的空位元素,R[m]为待移动到空位的元素。
当目标元素地址=首地址时,则移位完成。
2.考虑到p可能是n的因数,因此要通过移动次数j判断是否已移动n个元素;
若要移动多轮,则每一轮的移动首元素应+1,
因此,t表示共移动了几轮,R[t]表示本轮移动的首元素
*/
/*时间复杂度:O(n);空间复杂度:O(1) */
/*for循环的参数:
int j=0; //计数 共移动了几个元素
int t=0; //计数 共移动了几轮,R[t]表示本轮移动的首元素
j++; //每移动一次,则j+1
t++; //每移动完1轮,则t+1,t用于计算下一轮的首元素角标
*/
int i,m,x;
for(int j=0,t=0;j<n;j++,t++){ //外层while()执行的次数,即共移动了几轮
i = t; //设置新一轮的首元素角标
m = i + p; //设置新一轮的目标元素角标
x = R[i]; //将本轮首元素暂存于x
for(;m!=t;j++){ //逐个将目标元素移位到空位处,当m=t,则说明本轮移动完成。
R[i] = R[m]; //将目标元素移到空位元素处
i=m; //计算新的空位元素角标
(i+p<=n-1)?(m=i+p):(m=i+p-n); //计算新的目标元素角标
} //移动完一轮
R[i] = x; //本轮收尾:将暂存在x的首元素移到空位元素处
}
}
void myprint001(int R[],int n){ //功能:打印数组
for (int i=0;i<n-1;i++){
printf("%d ",R[i]);
}
printf("%d",R[n-1]);
}
代码 - Java
下面我再用Java实现一下,作为练习。C语言Java的代码基本相同,主要是录入数据部分、打印部分有差异,还有就是有个三元运算符在C语言中测试通过但是在Java中不通过,原因不明,于是就改写为显式if-else语句。
import java.io.*;
class Main{ //Java
public static void main(String[] args) throws IOException {
//功能:将数组元素循环右移p个元素
//这与2010年考研408的42题很像,只不过把向左移动改为了向右移动。
//录入数组数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] strArr = br.readLine().split(" +");
int n = Integer.parseInt(strArr[0]); //元素个数n
int p = Integer.parseInt(strArr[1]); //右移元素个数p
int t,a;
if(p%n==0) p = 0;
if(p>0) p = n - (p%n);
String[] strArr2 = br.readLine().split(" +");
int[] R = new int[n];
for(int i=0;i<n;i++){
t = Integer.parseInt(strArr2[i]);
R[i] = t;
}
//myprint001(R,n); //打印初始数组
//解法1:原地逆置法
Converse(R,n,p);
//解法2:辅助数组法
//Converse2(R,n,p);
//解法3:循环填空法
//myMove(R,n,p);
myprint001(R,n); //打印移位后的数组
}
public static void Converse(int R[],int n,int p){ //解法1
/*功能:将数组R的元素循环左移p个位次*/
/*实现思路:
利用三次原地逆置实现。
根据p的位置将数组看做ab两部分,
第一次逆置a,数组变为(-a)b,
第二次逆置b,数组变为(-a)(-b)
第三次逆置整个数组,数组变为ba。*/
/*时间复杂度:O(n);空间复杂度:O(1) */
Reverse(R,0,p-1);
Reverse(R,p,n-1);
Reverse(R,0,n-1);
}
public static void Reverse(int R[],int from,int to){
/*功能:将数组R中指定角标范围内的部分原地逆置*/
int i,temp; //i是计数器,temp用于暂存元素以便于逆置交换
for(i=0;i<(to-from+1)/2;i++){
temp = R[from+i];
R[from+i] = R[to-i];
R[to-i] = temp;
}
}
public static void Converse2(int R[],int n,int p){ //解法2
/*实现思路:
利用一个辅助数组S,暂存前p个元素,之后将后面的元素移位,
再将前p个元素移位到正确位置。
*/
/*时间复杂度:O(n) ;空间复杂度: O(p) */
int[] S = new int[p]; //创建一个辅助数组
for(int i=0;i<=p-1;i++) //将R中前p个元素移到S中
S[i] = R[i];
for(int i=p;i<n;i++) //将R中p及后面的元素移到正确位置
R[i-p] = R[i];
for(int i=0;i<=p-1;i++) //将S中的元素移到R中正确位置
R[n-p+i] = S[i];
}
public static void myMove(int R[],int n,int p){ //解法3
/* 接收的参数:
R[] 要重新排序的数组;n 数组R中元素的个数 ;p 要向左移动几位 */
/*功能:
将含有n个元素的int数组R中的元素循环左移p位 */
/*实现思路:
1.将首元素暂存于x,则首元素的位置视为空,接下来逐个移位填空。
移位时,R[i]为目前的空位元素,R[m]为待移动到空位的元素。
当目标元素地址=首地址时,则移位完成。
2.考虑到p可能是n的因数,因此要通过移动次数j判断是否已移动n个元素;
若要移动多轮,则每一轮的移动首元素应+1,
因此,t表示共移动了几轮,R[t]表示本轮移动的首元素
*/
/*时间复杂度:O(n);空间复杂度:O(1) */
/*for循环的参数:
int j=0; //计数 共移动了几个元素
int t=0; //计数 共移动了几轮,R[t]表示本轮移动的首元素
j++; //每移动一次,则j+1
t++; //每移动完1轮,则t+1,t用于计算下一轮的首元素角标
*/
int i,m,x;
for(int j=0,t=0;j<n;j++,t++){ //外层while()执行的次数,即共移动了几轮
i = t; //设置新一轮的首元素角标
m = i + p; //设置新一轮的目标元素角标
x = R[i]; //将本轮首元素暂存于x
for(;m!=t;j++){ //逐个将目标元素移位到空位处,当m=t,则说明本轮移动完成。
R[i] = R[m]; //将目标元素移到空位元素处
i=m; //计算新的空位元素角标
//(i+p<=n-1)?(m=i+p):(m=i+p-n); /*这句在C语言中测试成功,但换成Java就说这不是一个语句。*/
if(i+p<=n-1) //计算新的目标元素角标
m=i+p;
else
m=i+p-n;
} //移动完一轮
R[i] = x; //本轮收尾:将暂存在x的首元素移到空位元素处
}
}
public static void myprint001(int R[],int n){ //功能:打印数组
String s = "";
for (int i=0;i<n;i++){
s = s + R[i] + " ";
}
System.out.println(s.trim());
}
}
1009 说反话
题目
作者 CHEN, Yue
单位 浙江大学
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。
输入格式:
测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用 1 个空格分开,输入保证句子末尾没有多余的空格。
输出格式:
每个测试用例的输出占一行,输出倒序后的句子。
输入样例:
Hello World Here I Come
输出样例:
Come I Here World Hello
代码
import java.io.*;
class Main{ //功能:将给定英文字符串按单词倒序输出
//时间复杂度 O(n) 空间复杂度O(n) n为字符串长度
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] arr = br.readLine().split( " ");
//输出
String s = "";
for(int i = arr.length-1;i >= 0;i--)
s = s + (arr[i]) + " ";
System.out.println(s.trim());
}
}
1010 一元多项式求导
题目
作者 DS课程组
单位 浙江大学
设计函数求一元多项式的导数。(注:xn(n为整数)的一阶导数为nxn−1。)
输入格式:
以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过 1000 的整数)。数字间以空格分隔。
输出格式:
以与输入相同的格式输出导数多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。注意“零多项式”的指数和系数都是 0,但是表示为 0 0
。
输入样例:
3 4 -5 2 6 1 -2 0
输出样例:
12 3 -10 1 6 0
代码
/*
功能:多项式求导
实现思路:根据一元多项式求导法则,每两个整数为一组,假设为a b,
则求导结果为 a*b b-1 。利用循环遍历数组即可。
时间复杂度O(n) 空间复杂度O(n) n为给定字符串长度
*/
import java.io.*;
class Main{
public static void main(String[] args) throws IOException {
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] arrS = br.readLine().split(" +");
//数据格式转换
int[] arr = new int[arrS.length];
for(int i=0;i<arr.length;i++)
arr[i] = Integer.parseInt(arrS[i]);
//计算导数
for(int i=0;i<arr.length;i+=2){
arr[i] = arr[i] * arr[i+1]; //计算新的系数
arr[i+1]--; //计算新的指数
}
//输出结果
String s = "";
for(int i=0;i<arr.length;i+=2)
if(arr[i]!=0) //只输出非零项
s = s + arr[i] + " " + arr[i+1] + " ";
if(s.equals("")) s = "0 0"; //处理零多项式的情况
System.out.print(s.trim());
}
}
1011 A+B 和 C
题目
作者 HOU, Qiming
单位 浙江大学
给定区间 [−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
代码
/*
功能:判断给定的T组整数,每组A+B是否>C,并输出判断结果
实现思路:首先读取组数T,并循环处理每一组数据。
对于每一组数据,调用判断函数,直接求和。
时间复杂度O(n) 空间复杂度O(1)
*/
import java.io.*;
class Main{
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine().trim();
int t = Integer.parseInt(s); //录入待读取的组数并转为int
String[] arrS = new String[3]; //用于读取每一组的String数据
int[] arr = new int[3]; //用于存储每一组的int数据
String res = ""; //用于存储一行判断结果
//循环读取输入并判断
for(int i=0;i<t;i++){
arrS = br.readLine().split(" +"); //读取一组数据
for(int j=0;j<=2;j++) //将String转为int
arr[j] = Integer.parseInt(arrS[j]);
res = "" + isBigger(arr[0],arr[1],arr[2]); //计算判断结果
res = "Case #" + (i+1) + ": " + res + "\n"; //生成输出信息
System.out.print(res); //打印输出
}
}
private static boolean isBigger(int a,int b,int c){
//功能:给定三个int,判断是否 A+B>C
//对于A+B可能超出int范围的情况,单独判断
if(a>c && b>0) return true;
if(b>c && a>0) return true;
if(a<c && b<0) return false;
if(b<c && a<0) return false;
//判断剩下的情况
if(a+b-c>0) return true;
else return false;
}
}
1012 数字分类
题目
作者 CHEN, Yue
单位 浙江大学
给定一系列正整数,请按要求对数字进行分类,并输出以下 5 个数字:
- A1 = 能被 5 整除的数字中所有偶数的和;
- A2 = 将被 5 除后余 1 的数字按给出顺序进行交错求和,即计算 n1−n2+n3−n4⋯;
- A3 = 被 5 除后余 2 的数字的个数;
- A4 = 被 5 除后余 3 的数字的平均数,精确到小数点后 1 位;
- A5 = 被 5 除后余 4 的数字中最大数字。
输入格式:
每个输入包含 1 个测试用例。每个测试用例先给出一个不超过 1000 的正整数 N,随后给出 N 个不超过 1000 的待分类的正整数。数字间以空格分隔。
输出格式:
对给定的 N 个正整数,按题目要求计算 A1~A5 并在一行中顺序输出。数字间以空格分隔,但行末不得有多余空格。
若分类之后某一类不存在数字,则在相应位置输出 N
。
输入样例 1:
13 1 2 3 4 5 6 7 8 9 10 20 16 18
输出样例 1:
30 11 2 9.7 9
输入样例 2:
8 1 2 4 5 6 7 9 16
输出样例 2:
N 11 2 N 9
代码
/*
功能:对输入的一组正整数,计算五项数据并输出结果。
实现思路:采用在线处理的方式,即读取一个数字就更新一次A1-A5。
计算A1-A5时要注意,该分类若没有数字,最后要输出N 。
时间复杂度O(n) 空间复杂度O(1)
*/
import java.io.*;
class Main{
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s = br.readLine().trim().split(" +");
//数据格式转换
int num = Integer.parseInt(s[0]); //正整数的个数
int n[] = new int[num];
for(int i=0;i<num;i++) //将String转为int
n[i] = Integer.parseInt(s[i+1]);
//初始化
int a1 = 0; //能被5整除的数字中所有偶数的和 ∵正整数,∴若最后为0,则说明没有这样的数字
int a21 = 0; //被5整除后余1的数字个数
int a22 = 0; //被5整除后余1的数字的交叉求和
int a3 = 0; //被5整除后余2的数字个数 若结果为0,则说明没有这样的数字
int a41 = 0; //被5整除后余3的数字个数 若结果为0,则说明没有这样的数字
double a42 = 0; //被5整除后余3的数字求和
double a43 = 0; //被5整除后余3的数字的平均数
int a5 = 0; //被5整除后余4的数字中最大的数字 若结果为0,则说明没有这样的数字
//在线处理
int t; //辅助
for(int i=0;i<num;i++){
t = n[i];
switch(t%5) {
case 0:
if(t%10==0) a1 = a1 + t;
break;
case 1:
a21++;
if(a21%2==1) a22 = a22 + t;
else a22 = a22 - t;
break;
case 2:
a3++;
break;
case 3:
a41++;
a42 = a42 + t;
a43 = a42 / a41;
break;
case 4:
if(t>a5) a5 = t;
break;
}//switch
}//for
//输出结果
String str = "";
if(a1==0) str = str + "N ";
else str = str + a1 + " ";
if(a21==0) str = str + "N ";
else str = str + a22 + " ";
if(a3==0) str = str + "N ";
else str = str + a3 + " ";
if(a41==0) str = str + "N ";
else str = str + String.format("%.1f",a43) + " ";
if(a5==0) str = str + "N";
else str = str + a5;
System.out.print(str);
}
}
1013 数素数
题目
作者 CHEN, Yue
单位 浙江大学
令 Pi 表示第 i 个素数。现任给两个正整数 M≤N≤104,请输出 PM 到 PN 的所有素数。
输入格式:
输入在一行中给出 M 和 N,其间以空格分隔。
输出格式:
输出从 PM 到 PN 的所有素数,每 10 个数字占 1 行,其间以空格分隔,但行末不得有多余空格。
输入样例:
5 27
输出样例:
11 13 17 19 23 29 31 37 41 43
47 53 59 61 67 71 73 79 83 89
97 101 103
代码
/*
功能:给定两个整数M N,输出第M个素数到第N个素数之间的所有素数。
实现思路:从2开始计算素数,并计数,到达M时开始输出,到达N时停止。
*/
import java.io.*;
class Main{
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] arr = br.readLine().trim().split(" +");
int m = Integer.parseInt(arr[0]);
int n = Integer.parseInt(arr[1]);
//开始计算
int t=0; //当前行输出了几个数字
String s = ""; //存储待输出的当前行
int j = 0; //计数,共出现了几个质数
for(int i=2;j<n;i++){
if(ifsushu(i)){
j++;
if(j>=m){ //当前质数要输出
s = s + i + " ";
t++;
if(t==10){ //每十个数要换行
System.out.println(s.trim());
s = "";
t = 0;
}
}
}
}
if(!s.equals("")) System.out.println(s.trim());
}
//判断一个整数是否是素数 时间复杂度为O(√n)
private static boolean ifsushu(int t){
//判断特殊值
if(t==2 || t==3 || t==5) return true;
//若尾数不是1 3 7 9 则一定不是素数(10以上的数)
if(t%2==0 || t%5==0) return false;
//若此数不是6n+1或者6n-1,则一定不是素数(10以上的数)
if((t+1)%6!=0 && (t-1)%6!=0) return false;
//遍历检查(合数一定能分解为质数的乘积)
for(int i=1;Math.pow(6*i-1,2)<=t;i++)
if(t % (6*i-1) == 0 || t % (6*i+1) == 0)
return false;
return true;
}
}
1014 福尔摩斯的约会
题目
作者 CHEN, Yue
单位 浙江大学
大侦探福尔摩斯接到一张奇怪的字条:
我们约会吧!
3485djDkxh4hhGE
2984akDfkkkkggEdsb
s&hgsfdk
d&Hyscvnm
大侦探很快就明白了,字条上奇怪的乱码实际上就是约会的时间星期四 14:04
,因为前面两字符串中第 1 对相同的大写英文字母(大小写有区分)是第 4 个字母 D
,代表星期四;第 2 对相同的字符是 E
,那是第 5 个英文字母,代表一天里的第 14 个钟头(于是一天的 0 点到 23 点由数字 0 到 9、以及大写字母 A
到 N
表示);后面两字符串第 1 对相同的英文字母 s
出现在第 4 个位置(从 0 开始计数)上,代表第 4 分钟。现给定两对字符串,请帮助福尔摩斯解码得到约会的时间。
输入格式:
输入在 4 行中分别给出 4 个非空、不包含空格、且长度不超过 60 的字符串。
输出格式:
在一行中输出约会的时间,格式为 DAY HH:MM
,其中 DAY
是某星期的 3 字符缩写,即 MON
表示星期一,TUE
表示星期二,WED
表示星期三,THU
表示星期四,FRI
表示星期五,SAT
表示星期六,SUN
表示星期日。题目输入保证每个测试存在唯一解。
输入样例:
3485djDkxh4hhGE
2984akDfkkkkggEdsb
s&hgsfdk
d&Hyscvnm
输出样例:
THU 14:04
代码
/*
功能:根据给定的两个字符串中相同的字符及其出现的位置,输出结果。
使用 s.charAt(n) 来确定字符串s 在n位置的字符。
时间复杂度O(n) 空间复杂度O(n)
*/
import java.io.*;
class Main{
public static void main(String[] args) throws IOException{
//接收输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s1 = br.readLine().trim();
String s2 = br.readLine().trim();
String s3 = br.readLine().trim();
String s4 = br.readLine().trim();
//开始计算
String s = ""; //输出结果
char c = ' '; //辅助
int t = 0; //辅助
for(int i=t;i<s1.length();i++){ //解码星期几
c = s1.charAt(i);
if(c>='A' && c<='G') //如果s1的当前字符是英文大写字母中的前七个
if(c == s2.charAt(i)){ //如果s1当前字符与s2当前字符相等
s = "MONTUEWEDTHUFRISATSUN".substring((c-'A')*3,(c-'A')*3+3); //生成解码结果
t = i; //记住当前对比到第几个元素了
break; //解码完毕,退出for循环
}
}//for
for(int i=t+1;i<s1.length();i++){ //解码小时数
c = s1.charAt(i);
if((c>='0' && c<='9') || (c>='A' && c<='N')) //如果当前字符是0-9或A-N
if(c == s2.charAt(i)){ //如果s1当前字符与s2当前字符相等
if(c<='9') //生成解码结果
s = s + " 0" + (c-'0');
else
s = s + " " + (c-'A'+10);
break; //解码完毕,退出for循环
}
}//for
for(int i=0;i<s3.length();i++){ //解码分钟数
c = s3.charAt(i);
if((c>='a' && c<='z') || (c>='A' && c<='Z')) //若当前字符为英文字母
if(c == s4.charAt(i)){ //若s3 s4当前字符相等
if(i<=9) //生成解码结果
s = s + ":0" + i;
else
s = s + ":" + i;
break; //解码完毕,退出for循环
}
}
System.out.print(s.trim());
}//void main()
}//class Main
***后续题目在其它博文中更新***
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)